|
Hibernate example source code file (readonly.xml)
This example Hibernate source code file (readonly.xml) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Hibernate readonly.xml source code
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
~ indicated by the @author tags or express copyright attribution
~ statements applied by the authors. All third-party contributions are
~ distributed under license by Red Hat Middleware LLC.
~
~ This copyrighted material is made available to anyone wishing to use, modify,
~ copy, or redistribute it subject to the terms and conditions of the GNU
~ Lesser General Public License, as published by the Free Software Foundation.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
~ for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this distribution; if not, write to:
~ Free Software Foundation, Inc.
~ 51 Franklin Street, Fifth Floor
~ Boston, MA 02110-1301 USA
-->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
]>
<chapter id="readonly">
<title>Read-only entities
<important>
<para>
Hibernate's treatment of <emphasis>read-only entities may
differ from what you may have encountered elsewhere. Incorrect usage
may cause unexpected results.
</para>
</important>
<para>
When an entity is read-only:
<itemizedlist>
<listitem>
<para>
Hibernate does not dirty-check the entity's simple
properties or single-ended associations;
</para>
</listitem>
<listitem>
<para>
Hibernate will not update simple properties or updatable
single-ended associations;
</para>
</listitem>
<listitem>
<para>
Hibernate will not update the version of the read-only
entity if only simple properties or single-ended
updatable associations are changed;
</para>
</listitem>
</itemizedlist>
</para>
<para>
In some ways, Hibernate treats read-only entities the same as entities that are
not read-only:
<itemizedlist>
<listitem>
<para>
Hibernate cascades operations to associations as
defined in the entity mapping.
</para>
</listitem>
<listitem>
<para>
Hibernate updates the version if the entity has a
collection with changes that dirties the entity;
</para>
</listitem>
<listitem>
<para>
A read-only entity can be deleted.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Even if an entity is not read-only, its collection association can
be affected if it contains a read-only entity.
</para>
<para>
For details about the affect of read-only entities on different
property and association types, see
<xref linkend="readonly-proptypes"/>.
</para>
<para>
For details about how to make entities read-only, see
<xref linkend="readonly-api"/>
</para>
<para>
Hibernate does some optimizing for read-only entities:
</para>
<itemizedlist>
<listitem>
<para>
It saves execution time by not dirty-checking simple properties or
single-ended associations.
</para>
</listitem>
<listitem>
<para>
It saves memory by deleting database snapshots.
</para>
</listitem>
</itemizedlist>
<section id="readonly-api">
<title>Making persistent entities read-only
<para>
Only persistent entities can be made read-only. Transient and
detached entities must be put in persistent state before they
can be made read-only.
</para>
<para>
Hibernate provides the following ways to make persistent entities read-only:
</para>
<itemizedlist>
<listitem>
<para>
you can map an entity class as <emphasis>immutable;
when an entity of an immutable class is made persistent,
Hibernate automatically makes it read-only.
see <xref linkend="readonly-api-immutable"/> for details
</para>
</listitem>
<listitem>
<para>
you can change a default so that entities loaded
into the session by Hibernate are automatically
made read-only; see <xref linkend="readonly-api-loaddefault"/> for details
</para>
</listitem>
<listitem>
<para>
you can make an HQL query or criteria read-only so
that entities loaded when the query or criteria executes,
scrolls, or iterates, are automatically
made read-only; see <xref linkend="readonly-api-querycriteria"/> for details
</para>
</listitem>
<listitem>
<para>
you can make a persistent entity that is already in the
in the session read-only; see
<xref linkend="readonly-api-entity"/> for details
</para>
</listitem>
</itemizedlist>
<section id="readonly-api-immutable">
<title>Entities of immutable classes
<para>
When an entity instance of an immutable class is made
persistent, Hibernate automatically makes it read-only.
</para>
<para>
An entity of an immutable class can created
and deleted the same as an entity of a mutable class.
</para>
<para>
Hibernate treats a persistent entity of an immutable
class the same way as a read-only persistent entity
of a mutable class. The only exception is that
Hibernate will not allow an entity of an immutable
class to be changed so it is not read-only.
</para>
</section>
<section id="readonly-api-loaddefault">
<title>Loading persistent entities as read-only
<note>
<para>
Entities of immutable classes are automatically loaded
as read-only.
</para>
</note>
<para>
To change the default behavior so Hibernate loads entity
instances of mutable classes into the session and automatically
makes them read-only, call:
</para>
<programlisting role="Java">Session.setDefaultReadOnly( true );
<para>
To change the default back so entities loaded by Hibernate are not
made read-only, call:
</para>
<programlisting role="Java">Session.setDefaultReadOnly( false );
<para>
You can determine the current setting by calling:
</para>
<programlisting role="Java">Session.isDefaultReadOnly();
<para>
If Session.isDefaultReadOnly() returns true, entities loaded by
the following are automatically made read-only:
</para>
<itemizedlist>
<listitem>
<para>
Session.load()
</para>
</listitem>
<listitem>
<para>
Session.get()
</para>
</listitem>
<listitem>
<para>
Session.merge()
</para>
</listitem>
<listitem>
<para>
executing, scrolling, or iterating HQL queries and
criteria; to override this setting for a particular
HQL query or criteria see
<xref linkend="readonly-api-querycriteria"/>
</para>
</listitem>
</itemizedlist>
<para>
Changing this default has no effect on:
</para>
<itemizedlist>
<listitem>
<para>
persistent entities already in the session when the
default was changed
</para>
</listitem>
<listitem>
<para>
persistent entities that are refreshed via
Session.refresh(); a refreshed persistent
entity will only be read-only if it was
read-only before refreshing
</para>
</listitem>
<listitem>
<para>
persistent entities added by the application via
Session.persist(), Session.save(), and Session.update()
Session.saveOrUpdate()
</para>
</listitem>
</itemizedlist>
</section>
<section id="readonly-api-querycriteria">
<title>Loading read-only entities from an HQL query/criteria
<note>
<para>
Entities of immutable classes are automatically loaded
as read-only.
</para>
</note>
<para>
If Session.isDefaultReadOnly() returns false (the default)
when an HQL query or criteria executes, then entities
and proxies of mutable classes loaded by the query will
not be read-only.
</para>
<para>
You can override this behavior so that entities and proxies loaded
by an HQL query or criteria are automatically made read-only.
</para>
<para>
For an HQL query, call:
</para>
<programlisting role="Java">Query.setReadOnly( true );
<para>
<literal>Query.setReadOnly( true ) must be called before
<literal>Query.list(), Query.uniqueResult(),
<literal>Query.scroll(), or Query.iterate()
</para>
<para>
For an HQL criteria, call:
</para>
<programlisting role="Java">Criteria.setReadOnly( true );
<para>
<literal>Criteria.setReadOnly( true ) must be called before
<literal>Criteria.list(), Criteria.uniqueResult(),
or <literal>Criteria.scroll()
</para>
<para>
Entities and proxies that exist in the session before being returned
by an HQL query or criteria are not affected.
</para>
<para>
Uninitialized persistent collections returned by the query are
not affected. Later, when the collection is initialized,
entities loaded into the session will be read-only if
Session.isDefaultReadOnly() returns true.
</para>
<para>
Using <literal>Query.setReadOnly( true ) or
<literal>Criteria.setReadOnly( true ) works well
when a single HQL query or criteria loads all the entities and
intializes all the proxies and collections that the application
needs to be read-only.
</para>
<para>
When it is not possible to load and initialize all
necessary entities in a single query or criteria,
you can temporarily change the session default to load
entities as read-only before the query is executed.
Then you can explicitly initialize proxies and collections
before restoring the session default.
</para>
<programlisting role="Java">
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
setDefaultReadOnly( true );
Contract contract =
( Contract ) session.createQuery(
"from Contract where customerName = 'Sherman'" )
.uniqueResult();
Hibernate.initialize( contract.getPlan() );
Hibernate.initialize( contract.getVariations() );
Hibernate.initialize( contract.getNotes() );
setDefaultReadOnly( false );
...
tx.commit();
session.close();
</programlisting>
<para>
If Session.isDefaultReadOnly() returns true, then you can
use Query.setReadOnly( false ) and Criteria.setReadOnly( false )
to override this session setting and load entities that are
not read-only.
</para>
</section>
<section id="readonly-api-entity">
<title>Making a persistent entity read-only
<note>
<para>
Persistent entities of immutable classes are automatically
made read-only.
</para>
</note>
<para>
To make a persistent entity or proxy read-only, call:
</para>
<programlisting>Session.setReadOnly(entityOrProxy, true)
<para>
To change a read-only entity or proxy of a mutable class so
it is no longer read-only, call:
</para>
<programlisting>Session.setReadOnly(entityOrProxy, false)
<important>
<para>
When a read-only entity or proxy is changed so it is no longer
read-only, Hibernate assumes that the current state of the
read-only entity is consistent with its database representation.
If this is not true, then any non-flushed changes made before
or while the entity was read-only, will be ignored.
</para>
</important>
<para>
To throw away non-flushed changes and make the persistent entity
consistent with its database representation, call: </para>
<programlisting role="Java">session.refresh( entity );
<para>
To flush changes made before or while the entity
was read-only and make the database representation
consistent with the current state of the persistent
entity:
</para>
<programlisting role="Java">
// evict the read-only entity so it is detached
session.evict( entity );
// make the detached entity (with the non-flushed changes) persistent
session.update( entity );
// now entity is no longer read-only and its changes can be flushed
s.flush();
</programlisting>
</section>
</section>
<section id="readonly-proptypes">
<title>Read-only affect on property type
<para>
The following table summarizes how different property types are
affected by making an entity read-only.
</para>
<table frame="topbot" id="readonly-proptype-summary">
<title>Affect of read-only entity on property types
<tgroup cols="2">
<colspec colwidth="1*"/>
<colspec colwidth="1*"/>
<thead>
<row>
<entry>Property/Association Type
<entry>Changes flushed to DB?
</row>
</thead>
<tbody>
<row>
<entry>
Simple
<para>
(<xref linkend="readonly-proptypes-simple"/>)
</para>
</entry>
<entry>no*
</row>
<row>
<entry>
<para>Unidirectional one-to-one
<para>Unidirectional many-to-one
<para>
(<xref linkend="readonly-proptypes-singleended-unidir"/>)
</para>
</entry>
<entry>
<para>no*
<para>no*
</entry>
</row>
<row>
<entry>
<para>Unidirectional one-to-many
<para>Unidirectional many-to-many
<para>
(<xref linkend="readonly-proptypes-manyended-unidir"/>)
</para>
</entry>
<entry>
<para>yes
<para>yes
</entry>
</row>
<row>
<entry>
<para>Bidirectional one-to-one
<para>
(<xref linkend="readonly-proptypes-onetoone-bidir"/>)
</para>
</entry>
<entry>only if the owning entity is not read-only*
</row>
<row>
<entry>
<para>Bidirectional one-to-many/many-to-one
<para>inverse collection
<para>non-inverse collection
<para>
(<xref linkend="readonly-proptypes-onetomany-manytoone"/>)
</para>
</entry>
<entry>
<para>
<para>only added/removed entities that are not read-only*
<para>yes
</entry>
</row>
<row>
<entry>
<para>Bidirectional many-to-many
<para>
(<xref linkend="readonly-proptypes-manytomany-bidir"/>)
</para>
</entry>
<entry>yes
</row>
</tbody>
</tgroup>
</table>
<para>
* Behavior is different when the entity having the property/association
is read-only, compared to when it is not read-only.
</para>
<section id="readonly-proptypes-simple">
<title>Simple properties
<para>
When a persistent object is read-only, Hibernate does not
dirty-check simple properties.
</para>
<para>
Hibernate will not synchronize simple property state changes
to the database. If you have automatic versioning, Hibernate
will not increment the version if any simple properties change.
</para>
<programlisting role="Java">
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
// get a contract and make it read-only
Contract contract = ( Contract ) session.get( Contract.class, contractId );
session.setReadOnly( contract, true );
// contract.getCustomerName() is "Sherman"
contract.setCustomerName( "Yogi" );
tx.commit();
tx = session.beginTransaction();
contract = ( Contract ) session.get( Contract.class, contractId );
// contract.getCustomerName() is still "Sherman"
...
tx.commit();
session.close();
</programlisting>
</section>
<section id="readonly-prop-types-unidir">
<title>Unidirectional associations
<section id="readonly-proptypes-singleended-unidir">
<title>Unidirectional one-to-one and many-to-one
<para>
Hibernate treats unidirectional one-to-one and many-to-one
associations in the same way when the owning entity is
read-only.
</para>
<para>
We use the term <emphasis>unidirectional single-ended
association</emphasis> when referring to functionality
that is common to unidirectional one-to-one and many-to-one
associations.
</para>
<para>
Hibernate does not dirty-check unidirectional single-ended
associations when the owning entity is read-only.
</para>
<para>
If you change a read-only entity's reference to a
unidirectional single-ended association to null,
or to refer to a different entity, that change
will not be flushed to the database.
</para>
<note>
<para>
If an entity is of an immutable class,
then its references to unidirectional single-ended
associations must be assigned when that
entity is first created. Because the entity is
automatically made read-only, these references can
not be updated.
</para>
</note>
<para>
If automatic versioning is used, Hibernate will not
increment the version due to local changes to
unidirectional single-ended associations.
</para>
<para>
In the following examples, Contract has a unidirectional
many-to-one association with Plan. Contract cascades save and
update operations to the association.
</para>
<para>
The following shows that changing a read-only entity's
many-to-one association reference to null has no effect
on the entity's database representation.
</para>
<programlisting role="Java">// get a contract with an existing plan;
// make the contract read-only and set its plan to null
tx = session.beginTransaction();
Contract contract = ( Contract ) session.get( Contract.class, contractId );
session.setReadOnly( contract, true );
contract.setPlan( null );
tx.commit();
// get the same contract
tx = session.beginTransaction();
contract = ( Contract ) session.get( Contract.class, contractId );
// contract.getPlan() still refers to the original plan;
tx.commit();
session.close();</programlisting>
<para>
The following shows that, even though
an update to a read-only entity's many-to-one
association has no affect on the entity's
database representation, flush still cascades
the save-update operation to the locally
changed association.
</para>
<programlisting role="Java">// get a contract with an existing plan;
// make the contract read-only and change to a new plan
tx = session.beginTransaction();
Contract contract = ( Contract ) session.get( Contract.class, contractId );
session.setReadOnly( contract, true );
Plan newPlan = new Plan( "new plan"
contract.setPlan( newPlan);
tx.commit();
// get the same contract
tx = session.beginTransaction();
contract = ( Contract ) session.get( Contract.class, contractId );
newPlan = ( Contract ) session.get( Plan.class, newPlan.getId() );
// contract.getPlan() still refers to the original plan;
// newPlan is non-null because it was persisted when
// the previous transaction was committed;
tx.commit();
session.close();</programlisting>
</section>
<section id="readonly-proptypes-manyended-unidir">
<title>Unidirectional one-to-many and many-to-many
<para>
Hibernate treats unidirectional one-to-many
and many-to-many associations owned by a read-only
entity the same as when owned by an entity that is not
read-only.
</para>
<para>
Hibernate dirty-checks unidirectional one-to-many and
many-to-many associations;
</para>
<para>
The collection can contain entities that
are read-only, as well as entities
that are not read-only.
</para>
<para>
Entities can be added and removed from the
collection; changes are flushed to the database.
</para>
<para>
If automatic versioning is used, Hibernate will
update the version due to changes in the collection
if they dirty the owning entity.
</para>
</section>
</section>
<section id="readonly-proptypes-bidir">
<title>Bidirectional associations
<section id="readonly-proptypes-onetoone-bidir">
<title>Bidirectional one-to-one
<para>
If a read-only entity owns a bidirectional
one-to-one association:
</para>
<itemizedlist>
<listitem>
<para>
Hibernate does not dirty-check the association.
</para>
</listitem>
<listitem>
<para>
updates that change the association reference
to null or to refer to a different entity
will not be flushed to the database.
</para>
</listitem>
<listitem>
<para>
If automatic versioning is used, Hibernate will not
increment the version due to local changes to
the association.
</para>
</listitem>
</itemizedlist>
<note>
<para>
If an entity is of an immutable class,
and it owns a bidirectional one-to-one
association, then its reference must be
assigned when that entity is first created.
Because the entity is automatically made
read-only, these references cannot be updated.
</para>
</note>
<para>
When the owner is not read-only, Hibernate treats
an association with a read-only entity the same
as when the association is with an entity that is
not read-only.
</para>
</section>
<section id="readonly-proptypes-onetomany-manytoone">
<title>Bidirectional one-to-many/many-to-one
<para>
A read-only entity has no impact on a bidirectional
one-to-many/many-to-one association if:
</para>
<itemizedlist>
<listitem>
<para>
the read-only entity is on the one-to-many side
using an inverse collection;
</para>
</listitem>
<listitem>
<para>
the read-only entity is on the one-to-many side
using a non-inverse collection;
</para>
</listitem>
<listitem>
<para>
the one-to-many side uses a non-inverse collection
that contains the read-only entity
</para>
</listitem>
</itemizedlist>
<para>
When the one-to-many side uses an inverse collection:
</para>
<itemizedlist>
<listitem>
<para>
a read-only entity can only be added to the collection
when it is created;
</para>
</listitem>
<listitem>
<para>
a read-only entity can only be removed from the
collection by an orphan delete or by explicitly
deleting the entity.
</para>
</listitem>
</itemizedlist>
</section>
<section id="readonly-proptypes-manytomany-bidir">
<title>Bidirectional many-to-many
<para>
Hibernate treats bidirectional many-to-many
associations owned by a read-only entity the
same as when owned by an entity that is not
read-only.
</para>
<para>
Hibernate dirty-checks bidirectional many-to-many
associations.
</para>
<para>
The collection on either side of the association
can contain entities that are read-only, as well
as entities that are not read-only.
</para>
<para>
Entities are added and removed from both sides
of the collection; changes are flushed to the
database.
</para>
<para>
If automatic versioning is used, Hibernate will
update the version due to changes in both sides of
the collection if they dirty the entity owning the
respective collections.
</para>
</section>
</section>
</section>
</chapter>
Other Hibernate examples (source code examples)
Here is a short list of links related to this Hibernate readonly.xml source code file:
|