11.1. Making persistent entities read-only

优质
小牛编辑
129浏览
2023-12-01

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.

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 第 11.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 第 11.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 第 11.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 第 11.1.4 节 “Making a persistent entity read-only” for details

11.1.1. Entities of immutable classes

When an entity instance of an immutable class is made persistent, Hibernate automatically makes it read-only.

An entity of an immutable class can created and deleted the same as an entity of a mutable class.

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.

11.1.2. Loading persistent entities as read-only

注意

Entities of immutable classes are automatically loaded as read-only.

To change the default behavior so Hibernate loads entity instances of mutable classes into the session and automatically makes them read-only, call:

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();

If Session.isDefaultReadOnly() returns true, entities loaded by the following are automatically made read-only:

  • Session.load()

  • Session.get()

  • Session.merge()

  • executing, scrolling, or iterating HQL queries and criteria; to override this setting for a particular HQL query or criteria see 第 11.1.3 节 “Loading read-only entities from an HQL query/criteria”

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()

11.1.3. Loading read-only entities from an HQL query/criteria

注意

Entities of immutable classes are automatically loaded as read-only.

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.

You can override this behavior so that entities and proxies loaded by an HQL query or criteria are automatically made read-only.

For an HQL query, call:

Query.setReadOnly( true );

Query.setReadOnly( true ) must be called before Query.list(), Query.uniqueResult(), Query.scroll(), or Query.iterate()

For an HQL criteria, call:

Criteria.setReadOnly( true );

Criteria.setReadOnly( true ) must be called before Criteria.list(), Criteria.uniqueResult(), or Criteria.scroll()

Entities and proxies that exist in the session before being returned by an HQL query or criteria are not affected.

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.

Using Query.setReadOnly( true ) or 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.

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.

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();

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.

11.1.4. Making a persistent entity read-only

注意

Persistent entities of immutable classes are automatically made read-only.

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)

重要

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.

To throw away non-flushed changes and make the persistent entity consistent with its database representation, call:

session.refresh( entity );

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:

// 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();