By default, Hibernate3 uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.
If you set
Please be aware that access to a lazy association outside of the context of an open Hibernate session will result in an exception. For example:
Alternatively, you can use a non-lazy collection or association, by specifying
On the other hand, you can use join fetching, which is non-lazy by nature, instead of select fetching in a particular transaction. We will now explain how to customize the fetching strategy. In Hibernate3, the mechanisms for choosing a fetch strategy are identical for single-valued associations and collections.
If you set
hibernate.default_batch_fetch_size
, Hibernate will use the batch fetch optimization for lazy fetching. This optimization can also be enabled at a more granular level.Please be aware that access to a lazy association outside of the context of an open Hibernate session will result in an exception. For example:
s = sessions.openSession(); Transaction tx = s.beginTransaction(); User u = (User) s.createQuery("from User u where u.name=:userName") .setString("userName", userName).uniqueResult(); Map permissions = u.getPermissions(); tx.commit(); s.close(); Integer accessLevel = (Integer) permissions.get("accounts"); // Error!Since the permissions collection was not initialized when the
Session
was closed, the collection will not be able to load its state. Hibernate does not support lazy initialization for detached objects. This can be fixed by moving the code that reads from the collection to just before the transaction is committed.Alternatively, you can use a non-lazy collection or association, by specifying
lazy="false"
for the association mapping. However, it is intended that lazy initialization be used for almost all collections and associations. If you define too many non-lazy associations in your object model, Hibernate will fetch the entire database into memory in every transaction.On the other hand, you can use join fetching, which is non-lazy by nature, instead of select fetching in a particular transaction. We will now explain how to customize the fetching strategy. In Hibernate3, the mechanisms for choosing a fetch strategy are identical for single-valued associations and collections.
Select fetching (the default) is extremely vulnerable to N+1 selects problems, so we might want to enable join fetching in the mapping document:
Irrespective of the fetching strategy you use, the defined non-lazy graph is guaranteed to be loaded into memory. This might, however, result in several immediate selects being used to execute a particular HQL query.
Usually, the mapping document is not used to customize fetching. Instead, we keep the default behavior, and override it for a particular transaction, using
If you want to change the fetching strategy used by
A completely different approach to problems with N+1 selects is to use the second-level cache.
<set name="permissions" fetch="join"> <key column="userId"/> <one-to-many class="Permission"/> </set
<many-to-one name="mother" class="Cat" fetch="join"/>The
fetch
strategy defined in the mapping document affects:Usually, the mapping document is not used to customize fetching. Instead, we keep the default behavior, and override it for a particular transaction, using
left join fetch
in HQL. This tells Hibernate to fetch the association eagerly in the first select, using an outer join. In the Criteria
query API, you would usesetFetchMode(FetchMode.JOIN)
.If you want to change the fetching strategy used by
get()
or load()
, you can use a Criteria
query. For example:User user = (User) session.createCriteria(User.class) .setFetchMode("permissions", FetchMode.JOIN) .add( Restrictions.idEq(userId) ) .uniqueResult();This is Hibernate's equivalent of what some ORM solutions call a "fetch plan".
A completely different approach to problems with N+1 selects is to use the second-level cache.
No comments:
Post a Comment