Hibernate.orgCommunity Documentation
Hibernate's treatment of read-only entities may differ from what you may have encountered elsewhere. Incorrect usage may cause unexpected results.
When an entity is read-only:
Hibernate does not dirty-check the entity's simple properties or single-ended associations;
Hibernate will not update simple properties or updatable single-ended associations;
Hibernate will not update the version of the read-only entity if only simple properties or single-ended updatable associations are changed;
In some ways, Hibernate treats read-only entities the same as entities that are not read-only:
Hibernate cascades operations to associations as defined in the entity mapping.
Hibernate updates the version if the entity has a collection with changes that dirties the entity;
A read-only entity can be deleted.
Even if an entity is not read-only, its collection association can be affected if it contains a read-only entity.
For details about the affect of read-only entities on different property and association types, see Section 12.2, “Read-only affect on property type”.
For details about how to make entities read-only, see Section 12.1, “Making persistent entities read-only”
Hibernate does some optimizing for read-only entities:
It saves execution time by not dirty-checking simple properties or single-ended associations.
It saves memory by deleting database snapshots.
Hibernate provides the following ways to make persistent entities read-only:
you can map an entity class as immutable; when an entity of an immutable class is made persistent, Hibernate automatically makes it read-only. see Section 12.1.1, “Entities of immutable classes” for details
you can change a default so that entities loaded into the session by Hibernate are automatically made read-only; see Section 12.1.2, “Loading persistent entities as read-only” for details
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 Section 12.1.3, “Loading read-only entities from an HQL query/criteria” for details
you can make a persistent entity that is already in the in the session read-only; see Section 12.1.4, “Making a persistent entity read-only” for details
Session.setDefaultReadOnly( true );
To change the default back so entities loaded by Hibernate are not made read-only, call:
Session.setDefaultReadOnly( false );
You can determine the current setting by calling:
Session.isDefaultReadOnly();
Changing this default has no effect on:
persistent entities already in the session when the default was changed
persistent entities that are refreshed via Session.refresh(); a refreshed persistent entity will only be read-only if it was read-only before refreshing
persistent entities added by the application via Session.persist(), Session.save(), and Session.update() Session.saveOrUpdate()
Query.setReadOnly( true );
Criteria.setReadOnly( true );
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();
To make a persistent entity or proxy read-only, call:
Session.setReadOnly(entityOrProxy, true)
To change a read-only entity or proxy of a mutable class so it is no longer read-only, call:
Session.setReadOnly(entityOrProxy, false)
session.refresh( entity );
// 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();
Table 12.1. Affect of read-only entity on property types
Property/Association Type | Changes flushed to DB? |
---|---|
Simple | no* |
Unidirectional one-to-one Unidirectional many-to-one (Section 12.2.2.1, “Unidirectional one-to-one and many-to-one”) |
no* no* |
Unidirectional one-to-many Unidirectional many-to-many (Section 12.2.2.2, “Unidirectional one-to-many and many-to-many”) |
yes yes |
Bidirectional one-to-one | only if the owning entity is not read-only* |
Bidirectional one-to-many/many-to-one inverse collection non-inverse collection |
only added/removed entities that are not read-only* yes |
Bidirectional many-to-many | yes |
* Behavior is different when the entity having the property/association is read-only, compared to when it is not read-only.
When a persistent object is read-only, Hibernate does not dirty-check simple properties.
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();
// 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();
// 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();
Copyright © 2004 Red Hat, Inc.