Author: hardy.ferentschik
Date: 2010-07-15 11:58:43 -0400 (Thu, 15 Jul 2010)
New Revision: 19956
Modified:
core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
Log:
HHH-5380 Added annotations in the cache configuration mix
Modified: core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml
===================================================================
---
core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2010-07-15
09:27:56 UTC (rev 19955)
+++
core/trunk/documentation/manual/src/main/docbook/en-US/content/performance.xml 2010-07-15
15:58:43 UTC (rev 19956)
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
@@ -22,150 +22,128 @@
~ 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" [
+<!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="performance">
- <title>Improving performance</title>
+ <title>Improving performance</title>
- <section id="performance-fetching" revision="2">
- <title>Fetching strategies</title>
+ <section id="performance-fetching" revision="2">
+ <title>Fetching strategies</title>
- <para>
- Hibernate uses a <emphasis>fetching strategy</emphasis> to
- retrieve associated objects if the application needs to navigate the
association.
- Fetch strategies can be declared in the O/R mapping metadata, or over-ridden
by a
- particular HQL or <literal>Criteria</literal> query.
- </para>
+ <para>Hibernate uses a <emphasis>fetching strategy</emphasis> to
retrieve
+ associated objects if the application needs to navigate the association.
+ Fetch strategies can be declared in the O/R mapping metadata, or
+ over-ridden by a particular HQL or <literal>Criteria</literal>
+ query.</para>
- <para>
- Hibernate3 defines the following fetching strategies:
- </para>
+ <para>Hibernate3 defines the following fetching strategies:</para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Join fetching</emphasis>: Hibernate retrieves
the
- associated instance or collection in the same
<literal>SELECT</literal>,
- using an <literal>OUTER JOIN</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Select fetching</emphasis>: a second
<literal>SELECT</literal>
- is used to retrieve the associated entity or collection. Unless
- you explicitly disable lazy fetching by specifying
<literal>lazy="false"</literal>,
- this second select will only be executed when you access the
- association.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Subselect fetching</emphasis>: a second
<literal>SELECT</literal>
- is used to retrieve the associated collections for all entities
retrieved in a
- previous query or fetch. Unless you explicitly disable lazy fetching
by specifying
- <literal>lazy="false"</literal>, this second
select will only be executed when you
- access the association.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Batch fetching</emphasis>: an optimization
strategy
- for select fetching. Hibernate retrieves a batch of entity instances
- or collections in a single <literal>SELECT</literal> by
specifying
- a list of primary or foreign keys.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Hibernate also distinguishes between:
- </para>
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Join fetching</emphasis>: Hibernate retrieves
the
+ associated instance or collection in the same
+ <literal>SELECT</literal>, using an <literal>OUTER
+ JOIN</literal>.</para>
+ </listitem>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Immediate fetching</emphasis>: an association,
collection or
- attribute is fetched immediately when the owner is loaded.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Lazy collection fetching</emphasis>: a
collection is fetched
- when the application invokes an operation upon that collection. This
- is the default for collections.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>"Extra-lazy" collection
fetching</emphasis>: individual
- elements of the collection are accessed from the database as needed.
- Hibernate tries not to fetch the whole collection into memory unless
- absolutely needed. It is suitable for large collections.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Proxy fetching</emphasis>: a single-valued
association is
- fetched when a method other than the identifier getter is invoked
- upon the associated object.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>"No-proxy" fetching</emphasis>: a
single-valued association is
- fetched when the instance variable is accessed. Compared to proxy
fetching,
- this approach is less lazy; the association is fetched even when only
the
- identifier is accessed. It is also more transparent, since no proxy
is visible to
- the application. This approach requires buildtime bytecode
instrumentation
- and is rarely necessary.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Lazy attribute fetching</emphasis>: an
attribute or single
- valued association is fetched when the instance variable is accessed.
- This approach requires buildtime bytecode instrumentation and is
rarely
- necessary.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- We have two orthogonal notions here: <emphasis>when</emphasis> is
the association
- fetched and <emphasis>how</emphasis> is it fetched. It is
important that you do not
- confuse them. We use <literal>fetch</literal> to tune
performance. We can use
- <literal>lazy</literal> to define a contract for what data is
always available
- in any detached instance of a particular class.
- </para>
-
- <section id="performance-fetching-lazy">
- <title>Working with lazy associations</title>
-
- <para>
- 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.
- </para>
-
- <para>
- If you set
- <literal>hibernate.default_batch_fetch_size</literal>,
Hibernate will use the
- batch fetch optimization for lazy fetching. This optimization can also be
enabled
- at a more granular level.
- </para>
-
- <para>
- 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:
- </para>
-
- <programlisting role="JAVA"><![CDATA[s =
sessions.openSession();
+ <listitem>
+ <para><emphasis>Select fetching</emphasis>: a second
+ <literal>SELECT</literal> is used to retrieve the associated entity
or
+ collection. Unless you explicitly disable lazy fetching by specifying
+ <literal>lazy="false"</literal>, this second select will
only be
+ executed when you access the association.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Subselect fetching</emphasis>: a second
+ <literal>SELECT</literal> is used to retrieve the associated
+ collections for all entities retrieved in a previous query or fetch.
+ Unless you explicitly disable lazy fetching by specifying
+ <literal>lazy="false"</literal>, this second select will
only be
+ executed when you access the association.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Batch fetching</emphasis>: an optimization
strategy
+ for select fetching. Hibernate retrieves a batch of entity instances
+ or collections in a single <literal>SELECT</literal> by specifying a
+ list of primary or foreign keys.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Hibernate also distinguishes between:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><emphasis>Immediate fetching</emphasis>: an association,
+ collection or attribute is fetched immediately when the owner is
+ loaded.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Lazy collection fetching</emphasis>: a
collection is
+ fetched when the application invokes an operation upon that
+ collection. This is the default for collections.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>"Extra-lazy" collection
fetching</emphasis>:
+ individual elements of the collection are accessed from the database
+ as needed. Hibernate tries not to fetch the whole collection into
+ memory unless absolutely needed. It is suitable for large
+ collections.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Proxy fetching</emphasis>: a single-valued
association
+ is fetched when a method other than the identifier getter is invoked
+ upon the associated object.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>"No-proxy" fetching</emphasis>: a
single-valued
+ association is fetched when the instance variable is accessed.
+ Compared to proxy fetching, this approach is less lazy; the
+ association is fetched even when only the identifier is accessed. It
+ is also more transparent, since no proxy is visible to the
+ application. This approach requires buildtime bytecode instrumentation
+ and is rarely necessary.</para>
+ </listitem>
+
+ <listitem>
+ <para><emphasis>Lazy attribute fetching</emphasis>: an
attribute or
+ single valued association is fetched when the instance variable is
+ accessed. This approach requires buildtime bytecode instrumentation
+ and is rarely necessary.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>We have two orthogonal notions here:
<emphasis>when</emphasis> is
+ the association fetched and <emphasis>how</emphasis> is it fetched. It
is
+ important that you do not confuse them. We use <literal>fetch</literal>
to
+ tune performance. We can use <literal>lazy</literal> to define a
contract
+ for what data is always available in any detached instance of a particular
+ class.</para>
+
+ <section id="performance-fetching-lazy">
+ <title>Working with lazy associations</title>
+
+ <para>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.</para>
+
+ <para>If you set
<literal>hibernate.default_batch_fetch_size</literal>,
+ Hibernate will use the batch fetch optimization for lazy fetching. This
+ optimization can also be enabled at a more granular level.</para>
+
+ <para>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:</para>
+
+ <programlisting role="JAVA">s = sessions.openSession();
Transaction tx = s.beginTransaction();
User u = (User) s.createQuery("from User u where u.name=:userName")
@@ -175,1260 +153,1383 @@
tx.commit();
s.close();
-Integer accessLevel = (Integer) permissions.get("accounts"); //
Error!]]></programlisting>
+Integer accessLevel = (Integer) permissions.get("accounts"); //
Error!</programlisting>
- <para>
- Since the permissions collection was not initialized when the
- <literal>Session</literal> was closed, the collection will
not be able to
- load its state. <emphasis>Hibernate does not support lazy
initialization
- for detached objects</emphasis>. This can be fixed by moving the
code that reads
- from the collection to just before the transaction is committed.
- </para>
-
- <para>
- Alternatively, you can use a non-lazy collection or association,
- by specifying <literal>lazy="false"</literal> 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.
- </para>
-
- <para>
- 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.
- </para>
-
- </section>
-
- <section id="performance-fetching-custom"
revision="4">
- <title>Tuning fetch strategies</title>
-
- <para>
- Select fetching (the default) is extremely vulnerable to N+1 selects
problems,
- so we might want to enable join fetching in the mapping document:
- </para>
-
- <programlisting role="XML"><![CDATA[<set
name="permissions"
- fetch="join">
- <key column="userId"/>
- <one-to-many class="Permission"/>
-</set]]></programlisting>
+ <para>Since the permissions collection was not initialized when the
+ <literal>Session</literal> was closed, the collection will not be able
+ to load its state. <emphasis>Hibernate does not support lazy
+ initialization for detached objects</emphasis>. This can be fixed by
+ moving the code that reads from the collection to just before the
+ transaction is committed.</para>
- <programlisting role="XML"><![CDATA[<many-to-one
name="mother" class="Cat"
fetch="join"/>]]></programlisting>
+ <para>Alternatively, you can use a non-lazy collection or association,
+ by specifying <literal>lazy="false"</literal> 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.</para>
- <para>
- The <literal>fetch</literal> strategy defined in the mapping
document affects:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- retrieval via <literal>get()</literal> or
<literal>load()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- retrieval that happens implicitly when an association is navigated
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>Criteria</literal> queries
- </para>
- </listitem>
- <listitem>
- <para>
- HQL queries if <literal>subselect</literal> fetching is
used
- </para>
- </listitem>
- </itemizedlist>
+ <para>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.</para>
+ </section>
- <para>
- 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.
- </para>
+ <section id="performance-fetching-custom" revision="4">
+ <title>Tuning fetch strategies</title>
- <para>
- Usually, the mapping document is not used to customize fetching. Instead,
we
- keep the default behavior, and override it for a particular transaction,
using
- <literal>left join fetch</literal> in HQL. This tells
Hibernate to fetch
- the association eagerly in the first select, using an outer join. In the
- <literal>Criteria</literal> query API, you would use
- <literal>setFetchMode(FetchMode.JOIN)</literal>.
- </para>
-
- <para>
- If you want to change the fetching strategy used by
- <literal>get()</literal> or
<literal>load()</literal>, you can use a
- <literal>Criteria</literal> query. For example:
- </para>
-
- <programlisting role="JAVA"><![CDATA[User user = (User)
session.createCriteria(User.class)
+ <para>Select fetching (the default) is extremely vulnerable to N+1
+ selects problems, so we might want to enable join fetching in the
+ mapping document:</para>
+
+ <programlisting role="XML"><set
name="permissions"
+ fetch="join">
+ <key column="userId"/>
+ <one-to-many class="Permission"/>
+</set</programlisting>
+
+ <programlisting role="XML"><many-to-one
name="mother" class="Cat"
fetch="join"/></programlisting>
+
+ <para>The <literal>fetch</literal> strategy defined in the
mapping
+ document affects:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>retrieval via <literal>get()</literal> or
+ <literal>load()</literal></para>
+ </listitem>
+
+ <listitem>
+ <para>retrieval that happens implicitly when an association is
+ navigated</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>Criteria</literal> queries</para>
+ </listitem>
+
+ <listitem>
+ <para>HQL queries if <literal>subselect</literal> fetching
is
+ used</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>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.</para>
+
+ <para>Usually, the mapping document is not used to customize fetching.
+ Instead, we keep the default behavior, and override it for a particular
+ transaction, using <literal>left join fetch</literal> in HQL. This
tells
+ Hibernate to fetch the association eagerly in the first select, using an
+ outer join. In the <literal>Criteria</literal> query API, you would
use
+ <literal>setFetchMode(FetchMode.JOIN)</literal>.</para>
+
+ <para>If you want to change the fetching strategy used by
+ <literal>get()</literal> or <literal>load()</literal>, you
can use a
+ <literal>Criteria</literal> query. For example:</para>
+
+ <programlisting role="JAVA">User user = (User)
session.createCriteria(User.class)
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
- .uniqueResult();]]></programlisting>
-
- <para>
- This is Hibernate's equivalent of what some ORM solutions call a
"fetch plan".
- </para>
+ .uniqueResult();</programlisting>
- <para>
- A completely different approach to problems with N+1 selects is to use
the
- second-level cache.
- </para>
+ <para>This is Hibernate's equivalent of what some ORM solutions call a
+ "fetch plan".</para>
- </section>
+ <para>A completely different approach to problems with N+1 selects is to
+ use the second-level cache.</para>
+ </section>
- <section id="performance-fetching-proxies"
revision="2">
- <title>Single-ended association proxies</title>
+ <section id="performance-fetching-proxies" revision="2">
+ <title>Single-ended association proxies</title>
- <para>
- Lazy fetching for collections is implemented using Hibernate's own
implementation
- of persistent collections. However, a different mechanism is needed for
lazy
- behavior in single-ended associations. The target entity of the
association must
- be proxied. Hibernate implements lazy initializing proxies for persistent
objects
- using runtime bytecode enhancement which is accessed via the CGLIB
library.
- </para>
+ <para>Lazy fetching for collections is implemented using Hibernate's own
+ implementation of persistent collections. However, a different mechanism
+ is needed for lazy behavior in single-ended associations. The target
+ entity of the association must be proxied. Hibernate implements lazy
+ initializing proxies for persistent objects using runtime bytecode
+ enhancement which is accessed via the CGLIB library.</para>
- <para>
- At startup, Hibernate3 generates proxies by default for all persistent
classes
- and uses them to enable lazy fetching of
<literal>many-to-one</literal> and
- <literal>one-to-one</literal> associations.
- </para>
+ <para>At startup, Hibernate3 generates proxies by default for all
+ persistent classes and uses them to enable lazy fetching of
+ <literal>many-to-one</literal> and
<literal>one-to-one</literal>
+ associations.</para>
- <para>
- The mapping file may declare an interface to use as the proxy interface
for that
- class, with the <literal>proxy</literal> attribute. By
default, Hibernate uses a subclass
- of the class. <emphasis>The proxied class must implement a default
constructor
- with at least package visibility. This constructor is recommended for all
persistent classes</emphasis>.
- </para>
+ <para>The mapping file may declare an interface to use as the proxy
+ interface for that class, with the <literal>proxy</literal> attribute.
+ By default, Hibernate uses a subclass of the class. <emphasis>The
+ proxied class must implement a default constructor with at least package
+ visibility. This constructor is recommended for all persistent
+ classes</emphasis>.</para>
- <para>
- There are potential problems to note when extending this approach to
polymorphic classes.For example:
- </para>
+ <para>There are potential problems to note when extending this approach
+ to polymorphic classes.For example:</para>
- <programlisting role="XML"><![CDATA[<class
name="Cat" proxy="Cat">
+ <programlisting role="XML"><class name="Cat"
proxy="Cat">
......
- <subclass name="DomesticCat">
+ <subclass name="DomesticCat">
.....
- </subclass>
-</class>]]></programlisting>
+ </subclass>
+</class></programlisting>
- <para>
- Firstly, instances of <literal>Cat</literal> will never be
castable to
- <literal>DomesticCat</literal>, even if the underlying
instance is an
- instance of <literal>DomesticCat</literal>:
- </para>
+ <para>Firstly, instances of <literal>Cat</literal> will never be
+ castable to <literal>DomesticCat</literal>, even if the underlying
+ instance is an instance of
<literal>DomesticCat</literal>:</para>
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat)
session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
+ <programlisting role="JAVA">Cat cat = (Cat) session.load(Cat.class,
id); // instantiate a proxy (does not hit the db)
if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
DomesticCat dc = (DomesticCat) cat; // Error!
....
-}]]></programlisting>
+}</programlisting>
- <para>
- Secondly, it is possible to break proxy
<literal>==</literal>:
- </para>
+ <para>Secondly, it is possible to break proxy
+ <literal>==</literal>:</para>
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat)
session.load(Cat.class, id); // instantiate a Cat proxy
+ <programlisting role="JAVA">Cat cat = (Cat) session.load(Cat.class,
id); // instantiate a Cat proxy
DomesticCat dc =
(DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat
proxy!
-System.out.println(cat==dc); //
false]]></programlisting>
+System.out.println(cat==dc); // false</programlisting>
- <para>
- However, the situation is not quite as bad as it looks. Even though we
now have two references
- to different proxy objects, the underlying instance will still be the
same object:
- </para>
+ <para>However, the situation is not quite as bad as it looks. Even
+ though we now have two references to different proxy objects, the
+ underlying instance will still be the same object:</para>
- <programlisting role="JAVA"><![CDATA[cat.setWeight(11.0);
// hit the db to initialize the proxy
-System.out.println( dc.getWeight() ); // 11.0]]></programlisting>
+ <programlisting role="JAVA">cat.setWeight(11.0); // hit the db to
initialize the proxy
+System.out.println( dc.getWeight() ); // 11.0</programlisting>
- <para>
- Third, you cannot use a CGLIB proxy for a
<literal>final</literal> class or a class
- with any <literal>final</literal> methods.
- </para>
+ <para>Third, you cannot use a CGLIB proxy for a
<literal>final</literal>
+ class or a class with any <literal>final</literal>
methods.</para>
- <para>
- Finally, if your persistent object acquires any resources upon
instantiation (e.g. in
- initializers or default constructor), then those resources will also be
acquired by
- the proxy. The proxy class is an actual subclass of the persistent
class.
- </para>
+ <para>Finally, if your persistent object acquires any resources upon
+ instantiation (e.g. in initializers or default constructor), then those
+ resources will also be acquired by the proxy. The proxy class is an
+ actual subclass of the persistent class.</para>
- <para>
- These problems are all due to fundamental limitations in Java's
single inheritance model.
- To avoid these problems your persistent classes must each implement an
interface
- that declares its business methods. You should specify these interfaces
in the mapping file where
- <literal>CatImpl</literal> implements the interface
<literal>Cat</literal> and <literal>DomesticCatImpl</literal>
- implements the interface <literal>DomesticCat</literal>. For
example:
- </para>
+ <para>These problems are all due to fundamental limitations in Java's
+ single inheritance model. To avoid these problems your persistent
+ classes must each implement an interface that declares its business
+ methods. You should specify these interfaces in the mapping file where
+ <literal>CatImpl</literal> implements the interface
+ <literal>Cat</literal> and
<literal>DomesticCatImpl</literal> implements
+ the interface <literal>DomesticCat</literal>. For
example:</para>
- <programlisting role="XML"><![CDATA[<class
name="CatImpl" proxy="Cat">
+ <programlisting role="XML"><class name="CatImpl"
proxy="Cat">
......
- <subclass name="DomesticCatImpl" proxy="DomesticCat">
+ <subclass name="DomesticCatImpl"
proxy="DomesticCat">
.....
- </subclass>
-</class>]]></programlisting>
+ </subclass>
+</class></programlisting>
- <para>
- Then proxies for instances of <literal>Cat</literal> and
<literal>DomesticCat</literal> can be returned
- by <literal>load()</literal> or
<literal>iterate()</literal>.
- </para>
+ <para>Then proxies for instances of <literal>Cat</literal> and
+ <literal>DomesticCat</literal> can be returned by
+ <literal>load()</literal> or
<literal>iterate()</literal>.</para>
- <programlisting role="JAVA"><![CDATA[Cat cat = (Cat)
session.load(CatImpl.class, catid);
+ <programlisting role="JAVA">Cat cat = (Cat)
session.load(CatImpl.class, catid);
Iterator iter = session.createQuery("from CatImpl as cat where
cat.name='fritz'").iterate();
-Cat fritz = (Cat) iter.next();]]></programlisting>
+Cat fritz = (Cat) iter.next();</programlisting>
-
- <note><title>Note</title>
- <para>
- <literal>list()</literal> does not usually return proxies.
- </para>
- </note>
-
- <para>
- Relationships are also lazily initialized. This means you must declare
any properties to be of
- type <literal>Cat</literal>, not
<literal>CatImpl</literal>.
- </para>
+ <note>
+ <title>Note</title>
- <para>
- Certain operations do <emphasis>not</emphasis> require proxy
initialization:
- </para>
+ <para><literal>list()</literal> does not usually return
+ proxies.</para>
+ </note>
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>equals()</literal>: if the persistent class
does not override
- <literal>equals()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>hashCode()</literal>: if the persistent
class does not override
- <literal>hashCode()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- The identifier getter method
- </para>
- </listitem>
- </itemizedlist>
+ <para>Relationships are also lazily initialized. This means you must
+ declare any properties to be of type <literal>Cat</literal>, not
+ <literal>CatImpl</literal>.</para>
- <para>
- Hibernate will detect persistent classes that override
<literal>equals()</literal> or
- <literal>hashCode()</literal>.
- </para>
-
- <para>
- By choosing <literal>lazy="no-proxy"</literal>
instead of the default
- <literal>lazy="proxy"</literal>, you can avoid
problems associated with typecasting.
- However, buildtime bytecode instrumentation is required, and all
operations
- will result in immediate proxy initialization.
- </para>
+ <para>Certain operations do <emphasis>not</emphasis> require
proxy
+ initialization:</para>
- </section>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>equals()</literal>: if the persistent class
does not
+ override <literal>equals()</literal></para>
+ </listitem>
- <section id="performance-fetching-initialization"
revision="1">
- <title>Initializing collections and proxies</title>
+ <listitem>
+ <para><literal>hashCode()</literal>: if the persistent class
does
+ not override <literal>hashCode()</literal></para>
+ </listitem>
- <para>
- A <literal>LazyInitializationException</literal> will be
thrown by Hibernate if an uninitialized
- collection or proxy is accessed outside of the scope of the
<literal>Session</literal>, i.e., when
- the entity owning the collection or having the reference to the proxy is
in the detached state.
- </para>
+ <listitem>
+ <para>The identifier getter method</para>
+ </listitem>
+ </itemizedlist>
- <para>
- Sometimes a proxy or collection needs to be initialized before closing
the
- <literal>Session</literal>. You can force initialization by
calling
- <literal>cat.getSex()</literal> or
<literal>cat.getKittens().size()</literal>, for example.
- However, this can be confusing to readers of the code and it is not
convenient for generic code.
- </para>
+ <para>Hibernate will detect persistent classes that override
+ <literal>equals()</literal> or
<literal>hashCode()</literal>.</para>
- <para>
- The static methods <literal>Hibernate.initialize()</literal>
and <literal>Hibernate.isInitialized()</literal>,
- provide the application with a convenient way of working with lazily
initialized collections or
- proxies. <literal>Hibernate.initialize(cat)</literal> will
force the initialization of a proxy,
- <literal>cat</literal>, as long as its
<literal>Session</literal> is still open.
- <literal>Hibernate.initialize( cat.getKittens() )</literal>
has a similar effect for the collection
- of kittens.
- </para>
+ <para>By choosing <literal>lazy="no-proxy"</literal>
instead of the
+ default <literal>lazy="proxy"</literal>, you can avoid
problems
+ associated with typecasting. However, buildtime bytecode instrumentation
+ is required, and all operations will result in immediate proxy
+ initialization.</para>
+ </section>
- <para>
- Another option is to keep the <literal>Session</literal> open
until all required
- collections and proxies have been loaded. In some application
architectures,
- particularly where the code that accesses data using Hibernate, and the
code that
- uses it are in different application layers or different physical
processes, it
- can be a problem to ensure that the
<literal>Session</literal> is open when a
- collection is initialized. There are two basic ways to deal with this
issue:
- </para>
+ <section id="performance-fetching-initialization"
revision="1">
+ <title>Initializing collections and proxies</title>
- <itemizedlist>
- <listitem>
- <para>
- In a web-based application, a servlet filter can be used to close
the
- <literal>Session</literal> only at the end of a user
request, once
- the rendering of the view is complete (the <emphasis>Open
Session in
- View</emphasis> pattern). Of course, this places heavy
demands on the
- correctness of the exception handling of your application
infrastructure.
- It is vitally important that the
<literal>Session</literal> is closed and the
- transaction ended before returning to the user, even when an
exception occurs
- during rendering of the view. See the Hibernate Wiki for examples
of this
- "Open Session in View" pattern.
- </para>
- </listitem>
- <listitem>
- <para>
- In an application with a separate business tier, the business
logic must
- "prepare" all collections that the web tier needs
before
- returning. This means that the business tier should load all the
data and
- return all the data already initialized to the presentation/web
tier that
- is required for a particular use case. Usually, the application
calls
- <literal>Hibernate.initialize()</literal> for each
collection that will
- be needed in the web tier (this call must occur before the
session is closed)
- or retrieves the collection eagerly using a Hibernate query with
a
- <literal>FETCH</literal> clause or a
<literal>FetchMode.JOIN</literal> in
- <literal>Criteria</literal>. This is usually easier
if you adopt the
- <emphasis>Command</emphasis> pattern instead of a
<emphasis>Session Facade</emphasis>.
- </para>
- </listitem>
- <listitem>
- <para>
- You can also attach a previously loaded object to a new
<literal>Session</literal>
- with <literal>merge()</literal> or
<literal>lock()</literal> before
- accessing uninitialized collections or other proxies. Hibernate
does not,
- and certainly <emphasis>should</emphasis> not, do
this automatically since it
- would introduce impromptu transaction semantics.
- </para>
- </listitem>
- </itemizedlist>
+ <para>A <literal>LazyInitializationException</literal> will be
thrown by
+ Hibernate if an uninitialized collection or proxy is accessed outside of
+ the scope of the <literal>Session</literal>, i.e., when the entity
+ owning the collection or having the reference to the proxy is in the
+ detached state.</para>
- <para>
- Sometimes you do not want to initialize a large collection, but still
need some
- information about it, like its size, for example, or a subset of the
data.
- </para>
+ <para>Sometimes a proxy or collection needs to be initialized before
+ closing the <literal>Session</literal>. You can force initialization
by
+ calling <literal>cat.getSex()</literal> or
+ <literal>cat.getKittens().size()</literal>, for example. However, this
+ can be confusing to readers of the code and it is not convenient for
+ generic code.</para>
- <para>
- You can use a collection filter to get the size of a collection without
initializing it:
- </para>
+ <para>The static methods
<literal>Hibernate.initialize()</literal> and
+ <literal>Hibernate.isInitialized()</literal>, provide the application
+ with a convenient way of working with lazily initialized collections or
+ proxies. <literal>Hibernate.initialize(cat)</literal> will force the
+ initialization of a proxy, <literal>cat</literal>, as long as its
+ <literal>Session</literal> is still open.
<literal>Hibernate.initialize(
+ cat.getKittens() )</literal> has a similar effect for the collection of
+ kittens.</para>
- <programlisting role="JAVA"><![CDATA[( (Integer)
s.createFilter( collection, "select count(*)" ).list().get(0)
).intValue()]]></programlisting>
+ <para>Another option is to keep the <literal>Session</literal>
open
+ until all required collections and proxies have been loaded. In some
+ application architectures, particularly where the code that accesses
+ data using Hibernate, and the code that uses it are in different
+ application layers or different physical processes, it can be a problem
+ to ensure that the <literal>Session</literal> is open when a
collection
+ is initialized. There are two basic ways to deal with this issue:</para>
- <para>
- The <literal>createFilter()</literal> method is also used to
efficiently retrieve subsets
- of a collection without needing to initialize the whole collection:
- </para>
+ <itemizedlist>
+ <listitem>
+ <para>In a web-based application, a servlet filter can be used to
+ close the <literal>Session</literal> only at the end of a user
+ request, once the rendering of the view is complete (the
+ <emphasis>Open Session in View</emphasis> pattern). Of course,
this
+ places heavy demands on the correctness of the exception handling of
+ your application infrastructure. It is vitally important that the
+ <literal>Session</literal> is closed and the transaction ended
+ before returning to the user, even when an exception occurs during
+ rendering of the view. See the Hibernate Wiki for examples of this
+ "Open Session in View" pattern.</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[s.createFilter(
lazyCollection,
"").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+ <listitem>
+ <para>In an application with a separate business tier, the business
+ logic must "prepare" all collections that the web tier needs before
+ returning. This means that the business tier should load all the
+ data and return all the data already initialized to the
+ presentation/web tier that is required for a particular use case.
+ Usually, the application calls
+ <literal>Hibernate.initialize()</literal> for each collection that
+ will be needed in the web tier (this call must occur before the
+ session is closed) or retrieves the collection eagerly using a
+ Hibernate query with a <literal>FETCH</literal> clause or a
+ <literal>FetchMode.JOIN</literal> in
<literal>Criteria</literal>.
+ This is usually easier if you adopt the
<emphasis>Command</emphasis>
+ pattern instead of a <emphasis>Session
Facade</emphasis>.</para>
+ </listitem>
- </section>
+ <listitem>
+ <para>You can also attach a previously loaded object to a new
+ <literal>Session</literal> with
<literal>merge()</literal> or
+ <literal>lock()</literal> before accessing uninitialized
collections
+ or other proxies. Hibernate does not, and certainly
+ <emphasis>should</emphasis> not, do this automatically since it
+ would introduce impromptu transaction semantics.</para>
+ </listitem>
+ </itemizedlist>
- <section id="performance-fetching-batch">
- <title>Using batch fetching</title>
+ <para>Sometimes you do not want to initialize a large collection, but
+ still need some information about it, like its size, for example, or a
+ subset of the data.</para>
- <para>
- Using batch fetching, Hibernate can load several uninitialized
- proxies if one proxy is accessed. Batch fetching is an optimization of
the lazy select
- fetching strategy. There are two ways you can configure batch fetching:
on the class level and the collection level.
- </para>
+ <para>You can use a collection filter to get the size of a collection
+ without initializing it:</para>
- <para>
- Batch fetching for classes/entities is easier to understand. Consider the
following example:
- at runtime you have 25 <literal>Cat</literal> instances
loaded in a <literal>Session</literal>, and each
- <literal>Cat</literal> has a reference to its
<literal>owner</literal>, a <literal>Person</literal>.
- The <literal>Person</literal> class is mapped with a proxy,
<literal>lazy="true"</literal>. If you now
- iterate through all cats and call
<literal>getOwner()</literal> on each, Hibernate will, by default,
- execute 25 <literal>SELECT</literal> statements to retrieve
the proxied owners. You can tune this
- behavior by specifying a <literal>batch-size</literal> in the
mapping of <literal>Person</literal>:
- </para>
+ <programlisting role="JAVA">( (Integer) s.createFilter( collection,
"select count(*)" ).list().get(0) ).intValue()</programlisting>
- <programlisting role="XML"><![CDATA[<class
name="Person"
batch-size="10">...</class>]]></programlisting>
+ <para>The <literal>createFilter()</literal> method is also used
to
+ efficiently retrieve subsets of a collection without needing to
+ initialize the whole collection:</para>
- <para>
- Hibernate will now execute only three queries: the pattern is 10, 10, 5.
- </para>
+ <programlisting role="JAVA">s.createFilter( lazyCollection,
"").setFirstResult(0).setMaxResults(10).list();</programlisting>
+ </section>
- <para>
- You can also enable batch fetching of collections. For example, if each
<literal>Person</literal> has
- a lazy collection of <literal>Cat</literal>s, and 10 persons
are currently loaded in the
- <literal>Session</literal>, iterating through all persons
will generate 10 <literal>SELECT</literal>s,
- one for every call to <literal>getCats()</literal>. If you
enable batch fetching for the
- <literal>cats</literal> collection in the mapping of
<literal>Person</literal>, Hibernate can pre-fetch
- collections:
- </para>
+ <section id="performance-fetching-batch">
+ <title>Using batch fetching</title>
- <programlisting role="XML"><![CDATA[<class
name="Person">
- <set name="cats" batch-size="3">
+ <para>Using batch fetching, Hibernate can load several uninitialized
+ proxies if one proxy is accessed. Batch fetching is an optimization of
+ the lazy select fetching strategy. There are two ways you can configure
+ batch fetching: on the class level and the collection level.</para>
+
+ <para>Batch fetching for classes/entities is easier to understand.
+ Consider the following example: at runtime you have 25
+ <literal>Cat</literal> instances loaded in a
<literal>Session</literal>,
+ and each <literal>Cat</literal> has a reference to its
+ <literal>owner</literal>, a <literal>Person</literal>. The
+ <literal>Person</literal> class is mapped with a proxy,
+ <literal>lazy="true"</literal>. If you now iterate through
all cats and
+ call <literal>getOwner()</literal> on each, Hibernate will, by
default,
+ execute 25 <literal>SELECT</literal> statements to retrieve the
proxied
+ owners. You can tune this behavior by specifying a
+ <literal>batch-size</literal> in the mapping of
+ <literal>Person</literal>:</para>
+
+ <programlisting role="XML"><class name="Person"
batch-size="10">...</class></programlisting>
+
+ <para>Hibernate will now execute only three queries: the pattern is 10,
+ 10, 5.</para>
+
+ <para>You can also enable batch fetching of collections. For example, if
+ each <literal>Person</literal> has a lazy collection of
+ <literal>Cat</literal>s, and 10 persons are currently loaded in the
+ <literal>Session</literal>, iterating through all persons will
generate
+ 10 <literal>SELECT</literal>s, one for every call to
+ <literal>getCats()</literal>. If you enable batch fetching for the
+ <literal>cats</literal> collection in the mapping of
+ <literal>Person</literal>, Hibernate can pre-fetch
collections:</para>
+
+ <programlisting role="XML"><class
name="Person">
+ <set name="cats" batch-size="3">
...
- </set>
-</class>]]></programlisting>
+ </set>
+</class></programlisting>
- <para>
- With a <literal>batch-size</literal> of 3, Hibernate will
load 3, 3, 3, 1 collections in four
- <literal>SELECT</literal>s. Again, the value of the attribute
depends on the expected number of
- uninitialized collections in a particular
<literal>Session</literal>.
- </para>
+ <para>With a <literal>batch-size</literal> of 3, Hibernate will
load 3,
+ 3, 3, 1 collections in four <literal>SELECT</literal>s. Again, the
value
+ of the attribute depends on the expected number of uninitialized
+ collections in a particular <literal>Session</literal>.</para>
- <para>
- Batch fetching of collections is particularly useful if you have a nested
tree of items, i.e.
- the typical bill-of-materials pattern. However, a <emphasis>nested
set</emphasis> or a
- <emphasis>materialized path</emphasis> might be a better
option for read-mostly trees.
- </para>
+ <para>Batch fetching of collections is particularly useful if you have a
+ nested tree of items, i.e. the typical bill-of-materials pattern.
+ However, a <emphasis>nested set</emphasis> or a
<emphasis>materialized
+ path</emphasis> might be a better option for read-mostly trees.</para>
+ </section>
- </section>
+ <section id="performance-fetching-subselect">
+ <title>Using subselect fetching</title>
- <section id="performance-fetching-subselect">
- <title>Using subselect fetching</title>
+ <para>If one lazy collection or single-valued proxy has to be fetched,
+ Hibernate will load all of them, re-running the original query in a
+ subselect. This works in the same way as batch-fetching but without the
+ piecemeal loading.</para>
- <para>
- If one lazy collection or single-valued proxy has to be fetched,
Hibernate will load all of
- them, re-running the original query in a subselect. This works in the
same way as
- batch-fetching but without the piecemeal loading.
- </para>
-
- <!-- TODO: Write more about this -->
+ <!-- TODO: Write more about this -->
+ </section>
- </section>
+ <section id="performance-fetching-profiles">
+ <title>Fetch profiles</title>
- <section id="performance-fetching-profiles">
- <title>Fetch profiles</title>
+ <para>Another way to affect the fetching strategy for loading associated
+ objects is through something called a fetch profile, which is a named
+ configuration associated with the
+ <interfacename>org.hibernate.SessionFactory</interfacename> but
enabled,
+ by name, on the <interfacename>org.hibernate.Session</interfacename>.
+ Once enabled on a
<interfacename>org.hibernate.Session</interfacename>,
+ the fetch profile wull be in affect for that
+ <interfacename>org.hibernate.Session</interfacename> until it is
+ explicitly disabled.</para>
- <para>
- Another way to affect the fetching strategy for loading associated
objects is through something
- called a fetch profile, which is a named configuration associated with
the
- <interfacename>org.hibernate.SessionFactory</interfacename>
but enabled, by name, on the
- <interfacename>org.hibernate.Session</interfacename>. Once
enabled on a
- <interfacename>org.hibernate.Session</interfacename>, the
fetch profile wull be in affect for
- that <interfacename>org.hibernate.Session</interfacename>
until it is explicitly disabled.
- </para>
- <para>
- So what does that mean? Well lets explain that by way of an example.
Say we have
- the following mappings:
- </para>
- <programlisting
role="XML"><![CDATA[<hibernate-mapping>
- <class name="Customer">
+ <para>So what does that mean? Well lets explain that by way of an
+ example. Say we have the following mappings:</para>
+
+ <programlisting role="XML"><hibernate-mapping>
+ <class name="Customer">
...
- <set name="orders" inverse="true">
- <key column="cust_id"/>
- <one-to-many class="Order"/>
- </set>
- </class>
- <class name="Order">
+ <set name="orders" inverse="true">
+ <key column="cust_id"/>
+ <one-to-many class="Order"/>
+ </set>
+ </class>
+ <class name="Order">
...
- </class>
-</hibernate-mapping>]]></programlisting>
- <para>
- Now normally when you get a reference to a particular customer, that
customer's set of
- orders will be lazy meaning we will not yet have loaded those orders from
the database.
- Normally this is a good thing. Now lets say that you have a certain use
case where
- it is more efficient to load the customer and their orders together. One
way certainly is
- to use "dynamic fetching" strategies via an HQL or criteria
queries. But another option is
- to use a fetch profile to achieve that. Just add the following to your
mapping:
- </para>
- <programlisting
role="XML"><![CDATA[<hibernate-mapping>
+ </class>
+</hibernate-mapping></programlisting>
+
+ <para>Now normally when you get a reference to a particular customer,
+ that customer's set of orders will be lazy meaning we will not yet have
+ loaded those orders from the database. Normally this is a good thing.
+ Now lets say that you have a certain use case where it is more efficient
+ to load the customer and their orders together. One way certainly is to
+ use "dynamic fetching" strategies via an HQL or criteria queries. But
+ another option is to use a fetch profile to achieve that. Just add the
+ following to your mapping:</para>
+
+ <programlisting role="XML"><hibernate-mapping>
...
- <fetch-profile name="customer-with-orders">
- <fetch entity="Customer" association="orders"
style="join"/>
- </fetch-profile>
-</hibernate-mapping>]]></programlisting>
- <para>
- or even:
- </para>
- <programlisting
role="XML"><![CDATA[<hibernate-mapping>
- <class name="Customer">
+ <fetch-profile name="customer-with-orders">
+ <fetch entity="Customer" association="orders"
style="join"/>
+ </fetch-profile>
+</hibernate-mapping></programlisting>
+
+ <para>or even:</para>
+
+ <programlisting role="XML"><hibernate-mapping>
+ <class name="Customer">
...
- <fetch-profile name="customer-with-orders">
- <fetch association="orders" style="join"/>
- </fetch-profile>
- </class>
+ <fetch-profile name="customer-with-orders">
+ <fetch association="orders" style="join"/>
+ </fetch-profile>
+ </class>
...
-</hibernate-mapping>]]></programlisting>
- <para>
- Now the following code will actually load both the customer
<emphasis>and their orders</emphasis>:
- </para>
- <programlisting role="JAVA"><![CDATA[
+</hibernate-mapping></programlisting>
+
+ <para>Now the following code will actually load both the customer
+ <emphasis>and their orders</emphasis>:</para>
+
+ <programlisting role="JAVA">
Session session = ...;
session.enableFetchProfile( "customer-with-orders" ); // name matches from
mapping
Customer customer = (Customer) session.get( Customer.class, customerId );
-]]></programlisting>
- <para>
- Currently only join style fetch profiles are supported, but they plan is
to support additional
- styles. See <ulink
url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3...
- for details.
- </para>
- </section>
+</programlisting>
- <section id="performance-fetching-lazyproperties">
- <title>Using lazy property fetching</title>
+ <para>Currently only join style fetch profiles are supported, but they
+ plan is to support additional styles. See <ulink
+
url="http://opensource.atlassian.com/projects/hibernate/browse/HHH-3...
+ for details.</para>
+ </section>
- <para>
- Hibernate3 supports the lazy fetching of individual properties. This
optimization technique
- is also known as <emphasis>fetch groups</emphasis>. Please
note that this is mostly a
- marketing feature; optimizing row reads is much more important than
- optimization of column reads. However, only loading some properties of a
class could
- be useful in extreme cases. For example, when legacy tables have hundreds
of columns and the data model
- cannot be improved.
- </para>
+ <section id="performance-fetching-lazyproperties">
+ <title>Using lazy property fetching</title>
- <para>
- To enable lazy property loading, set the
<literal>lazy</literal> attribute on your
- particular property mappings:
- </para>
+ <para>Hibernate3 supports the lazy fetching of individual properties.
+ This optimization technique is also known as <emphasis>fetch
+ groups</emphasis>. Please note that this is mostly a marketing feature;
+ optimizing row reads is much more important than optimization of column
+ reads. However, only loading some properties of a class could be useful
+ in extreme cases. For example, when legacy tables have hundreds of
+ columns and the data model cannot be improved.</para>
- <programlisting role="XML"><![CDATA[<class
name="Document">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name" not-null="true"
length="50"/>
- <property name="summary" not-null="true"
length="200" lazy="true"/>
- <property name="text" not-null="true" length="2000"
lazy="true"/>
-</class>]]></programlisting>
+ <para>To enable lazy property loading, set the
<literal>lazy</literal>
+ attribute on your particular property mappings:</para>
- <para>
- Lazy property loading requires buildtime bytecode instrumentation. If
your persistent
- classes are not enhanced, Hibernate will ignore lazy property settings
and
- return to immediate fetching.
- </para>
+ <programlisting role="XML"><class
name="Document">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name" not-null="true"
length="50"/>
+ <property name="summary" not-null="true"
length="200" lazy="true"/>
+ <property name="text" not-null="true"
length="2000" lazy="true"/>
+</class></programlisting>
- <para>
- For bytecode instrumentation, use the following Ant task:
- </para>
+ <para>Lazy property loading requires buildtime bytecode instrumentation.
+ If your persistent classes are not enhanced, Hibernate will ignore lazy
+ property settings and return to immediate fetching.</para>
- <programlisting role="XML"><![CDATA[<target
name="instrument" depends="compile">
- <taskdef name="instrument"
classname="org.hibernate.tool.instrument.InstrumentTask">
- <classpath path="${jar.path}"/>
- <classpath path="${classes.dir}"/>
- <classpath refid="lib.class.path"/>
- </taskdef>
+ <para>For bytecode instrumentation, use the following Ant task:</para>
- <instrument verbose="true">
- <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
- <include name="*.class"/>
- </fileset>
- </instrument>
-</target>]]></programlisting>
+ <programlisting role="XML"><target
name="instrument" depends="compile">
+ <taskdef name="instrument"
classname="org.hibernate.tool.instrument.InstrumentTask">
+ <classpath path="${jar.path}"/>
+ <classpath path="${classes.dir}"/>
+ <classpath refid="lib.class.path"/>
+ </taskdef>
- <para>
- A different way of avoiding unnecessary column reads, at least for
- read-only transactions, is to use the projection features of HQL or
Criteria
- queries. This avoids the need for buildtime bytecode processing and is
- certainly a preferred solution.
- </para>
-
- <para>
- You can force the usual eager fetching of properties using
<literal>fetch all
- properties</literal> in HQL.
- </para>
+ <instrument verbose="true">
+ <fileset
dir="${testclasses.dir}/org/hibernate/auction/model">
+ <include name="*.class"/>
+ </fileset>
+ </instrument>
+</target></programlisting>
- </section>
+ <para>A different way of avoiding unnecessary column reads, at least for
+ read-only transactions, is to use the projection features of HQL or
+ Criteria queries. This avoids the need for buildtime bytecode processing
+ and is certainly a preferred solution.</para>
+
+ <para>You can force the usual eager fetching of properties using
+ <literal>fetch all properties</literal> in HQL.</para>
</section>
+ </section>
- <section id="performance-cache" revision="1">
- <title>The Second Level Cache</title>
+ <section id="performance-cache" revision="1">
+ <title>The Second Level Cache</title>
- <para>
- A Hibernate <literal>Session</literal> is a transaction-level
cache of persistent data. It is
- possible to configure a cluster or JVM-level
(<literal>SessionFactory</literal>-level) cache on
- a class-by-class and collection-by-collection basis. You can even plug in a
clustered cache. Be
- aware that caches are not aware of changes made to the persistent store by
another application.
- They can, however, be configured to regularly expire cached data.
- </para>
-
- <para revision="1">
- You have the option to tell Hibernate which caching implementation to use by
- specifying the name of a class that implements
<literal>org.hibernate.cache.CacheProvider</literal>
- using the property
<literal>hibernate.cache.provider_class</literal>. Hibernate
- is bundled with a number of built-in integrations with the open-source cache
providers
- that are listed below. You can also implement your own and plug it in as
- outlined above. Note that versions prior to 3.2 use EhCache as the default
- cache provider.
- </para>
+ <para>A Hibernate <literal>Session</literal> is a transaction-level
cache
+ of persistent data. It is possible to configure a cluster or JVM-level
+ (<literal>SessionFactory</literal>-level) cache on a class-by-class and
+ collection-by-collection basis. You can even plug in a clustered cache. Be
+ aware that caches are not aware of changes made to the persistent store by
+ another application. They can, however, be configured to regularly expire
+ cached data.</para>
- <table frame="topbot" id="cacheproviders"
revision="1">
- <title>Cache Providers</title>
- <tgroup cols='5' align='left' colsep='1'
rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="3*"/>
- <colspec colname='c3' colwidth="1*"/>
- <colspec colname='c4' colwidth="1*"/>
- <colspec colname='c5' colwidth="1*"/>
- <thead>
+ <para revision="1">You have the option to tell Hibernate which
caching
+ implementation to use by specifying the name of a class that implements
+ <literal>org.hibernate.cache.CacheProvider</literal> using the property
+ <literal>hibernate.cache.provider_class</literal>. Hibernate is bundled
+ with a number of built-in integrations with the open-source cache
+ providers that are listed in <xref linkend="cacheproviders" />. You
can
+ also implement your own and plug it in as outlined above. Note that
+ versions prior to Hibernate 3.2 use EhCache as the default cache
+ provider.</para>
+
+ <table frame="topbot" id="cacheproviders"
revision="1">
+ <title>Cache Providers</title>
+
+ <tgroup align="left" cols="5" colsep="1"
rowsep="1">
+ <colspec colname="c1" colwidth="1*" />
+
+ <colspec colname="c2" colwidth="3*" />
+
+ <colspec colname="c3" colwidth="1*" />
+
+ <colspec colname="c4" colwidth="1*" />
+
+ <colspec colname="c5" colwidth="1*" />
+
+ <thead>
+ <row>
+ <entry>Cache</entry>
+
+ <entry>Provider class</entry>
+
+ <entry>Type</entry>
+
+ <entry>Cluster Safe</entry>
+
+ <entry>Query Cache Supported</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>Hashtable (not intended for production use)</entry>
+
+
<entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+
+ <entry>memory</entry>
+
+ <entry></entry>
+
+ <entry>yes</entry>
+ </row>
+
+ <row>
+ <entry>EHCache</entry>
+
+
<entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+
+ <entry>memory, disk</entry>
+
+ <entry></entry>
+
+ <entry>yes</entry>
+ </row>
+
+ <row>
+ <entry>OSCache</entry>
+
+
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+
+ <entry>memory, disk</entry>
+
+ <entry></entry>
+
+ <entry>yes</entry>
+ </row>
+
+ <row>
+ <entry>SwarmCache</entry>
+
+
<entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+
+ <entry>clustered (ip multicast)</entry>
+
+ <entry>yes (clustered invalidation)</entry>
+
+ <entry></entry>
+ </row>
+
+ <row>
+ <entry>JBoss Cache 1.x</entry>
+
+
<entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+
+ <entry>clustered (ip multicast), transactional</entry>
+
+ <entry>yes (replication)</entry>
+
+ <entry>yes (clock sync req.)</entry>
+ </row>
+
+ <row>
+ <entry>JBoss Cache 2</entry>
+
+
<entry><literal>org.hibernate.cache.jbc.JBossCacheRegionFactory</literal></entry>
+
+ <entry>clustered (ip multicast), transactional</entry>
+
+ <entry>yes (replication or invalidation)</entry>
+
+ <entry>yes (clock sync req.)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <section id="performance-cache-mapping" revision="2">
+ <title>Cache mappings</title>
+
+ <para>As we have done in previous chapters we are looking at the two
+ different possibiltites to configure caching. First configuration via
+ annotations and then via Hibernate mapping files.</para>
+
+ <para>By default, entities are not part of the second level cache and we
+ recommend you to stick to this setting. However, you can override this
+ by setting the <literal>shared-cache-mode</literal> element in your
+ <filename>persistence.xml</filename> file or by using the
+ <literal>javax.persistence.sharedCache.mode </literal>property in your
+ configuration. The following values are possible:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>ENABLE_SELECTIVE</literal> (Default and
recommended
+ value): entities are not cached unless explicitly marked as
+ cacheable.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>DISABLE_SELECTIVE</literal>: entities are
cached
+ unless explicitly marked as not cacheable.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>ALL</literal>: all entities are always cached
even if
+ marked as non cacheable.</para>
+ </listitem>
+
+ <listitem>
+ <para><literal>NONE</literal>: no entity are cached even if
marked
+ as cacheable. This option can make sense to disable second-level
+ cache altogether.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The cache concurrency strategy used by default can be set globaly
+ via the
+ <literal>hibernate.cache.default_cache_concurrency_strategy</literal>
+ configuration property. The values for this property are:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><literal>read-only</literal></para>
+ </listitem>
+
+ <listitem>
+ <para><literal>read-write</literal></para>
+ </listitem>
+
+ <listitem>
+ <para><literal>nonstrict-read-write</literal></para>
+ </listitem>
+
+ <listitem>
+ <para><literal>transactional</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <note>
+ <para>It is recommended to define the cache concurrency strategy per
+ entity rather than using a global one. Use the
+ <classname>(a)org.hibernate.annotations.Cache</classname> annotation
for
+ that.</para>
+ </note>
+
+ <example id="example-cache-concurrency-with-cache-annotation">
+ <title>Definition of cache concurrency strategy via
+ <classname>@Cache</classname></title>
+
+ <programlisting language="JAVA" role="JAVA">@Entity
+@Cacheable
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
+public class Forest { ... }</programlisting>
+ </example>
+
+ <para>Hibernate also let's you cache the content of a collection or the
+ identifiers if the collection contains other entities. Use the
+ <classname>@Cache</classname> annotation on the collection
+ property.</para>
+
+ <example>
+ <title>Caching collections using annotations</title>
+
+ <programlisting language="JAVA"
role="JAVA">(a)OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
+@JoinColumn(name="CUST_ID")
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
+public SortedSet<Ticket> getTickets() {
+ return tickets;
+}</programlisting>
+ </example>
+
+ <para><xref linkend="example-cache-annotation-with-attributes"
/>shows
+ the<literal> @org.hibernate.annotations.Cache</literal> annotations
with
+ its attributes. It allows you to define the caching strategy and region
+ of a given second level cache.</para>
+
+ <example id="example-cache-annotation-with-attributes">
+ <title><classname>@Cache</classname> annotation with
+ attributes</title>
+
+ <programlistingco>
+ <areaspec>
+ <area coords="2" id="cache-hm1" />
+
+ <area coords="3" id="cache-hm2" />
+
+ <area coords="4" id="cache-hm3" />
+ </areaspec>
+
+ <programlisting>@Cache(
+ CacheConcurrencyStrategy usage();
+ String region() default "";
+ String include() default "all";
+)</programlisting>
+
+ <calloutlist>
+ <callout arearefs="cache-hm1">
+ <para>usage: the given cache concurrency strategy (NONE,
+ READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE,
+ TRANSACTIONAL)</para>
+ </callout>
+
+ <callout arearefs="cache-hm2">
+ <para>region (optional): the cache region (default to the fqcn
+ of the class or the fq role name of the collection)</para>
+ </callout>
+
+ <callout arearefs="cache-hm3">
+ <para><literal>include</literal> (optional): all to
include all
+ properties, non-lazy to only include non lazy properties
+ (default all).</para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ </example>
+
+ <para>Let's now take a look at Hibernate mapping files. There the
+ <literal><cache></literal> element of a class or
collection
+ mapping is used to configure the second level cache. Looking at <xref
+ linkend="example-hibernate-cache-mapping-element" /> the parallels to
+ anotations is obvious.</para>
+
+ <example id="example-hibernate-cache-mapping-element">
+ <title>The Hibernate <literal><cache></literal>
mapping
+ element</title>
+
+ <programlistingco>
+ <areaspec>
+ <area coords="2" id="cache1" />
+
+ <area coords="3" id="cache2" />
+
+ <area coords="4" id="cache3" />
+ </areaspec>
+
+ <programlisting><cache
+ usage="transactional|read-write|nonstrict-read-write|read-only"
+ region="RegionName"
+ include="all|non-lazy"
+/></programlisting>
+
+ <calloutlist>
+ <callout arearefs="cache1">
+ <para><literal>usage</literal> (required) specifies the
caching
+ strategy: <literal>transactional</literal>,
+ <literal>read-write</literal>,
+ <literal>nonstrict-read-write</literal> or
+ <literal>read-only</literal></para>
+ </callout>
+
+ <callout arearefs="cache2">
+ <para><literal>region</literal> (optional: defaults to
the class
+ or collection role name): specifies the name of the second level
+ cache region</para>
+ </callout>
+
+ <callout arearefs="cache3">
+ <para><literal>include</literal> (optional: defaults to
+ <literal>all</literal>)
<literal>non-lazy</literal>: specifies
+ that properties of the entity mapped with
+ <literal>lazy="true"</literal> cannot be cached when
+ attribute-level lazy fetching is enabled</para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ </example>
+
+ <para>Alternatively to <literal><cache></literal>,
you can use
+ <literal><class-cache></literal> and
+ <literal><collection-cache></literal> elements in
+ <literal>hibernate.cfg.xml</literal>.</para>
+
+ <para>Let's now have a closer look at the different usage
+ strategies</para>
+ </section>
+
+ <section id="performance-cache-readonly">
+ <title>Strategy: read only</title>
+
+ <para>If your application needs to read, but not modify, instances of a
+ persistent class, a <literal>read-only</literal> cache can be used.
This
+ is the simplest and optimal performing strategy. It is even safe for use
+ in a cluster.</para>
+ </section>
+
+ <section id="performance-cache-readwrite">
+ <title>Strategy: read/write</title>
+
+ <para>If the application needs to update data, a
+ <literal>read-write</literal> cache might be appropriate. This cache
+ strategy should never be used if serializable transaction isolation
+ level is required. If the cache is used in a JTA environment, you must
+ specify the property
+ <literal>hibernate.transaction.manager_lookup_class</literal> and
naming
+ a strategy for obtaining the JTA
<literal>TransactionManager</literal>.
+ In other environments, you should ensure that the transaction is
+ completed when <literal>Session.close()</literal> or
+ <literal>Session.disconnect()</literal> is called. If you want to use
+ this strategy in a cluster, you should ensure that the underlying cache
+ implementation supports locking. The built-in cache providers
+ <emphasis>do not</emphasis> support locking.</para>
+ </section>
+
+ <section id="performance-cache-nonstrict">
+ <title>Strategy: nonstrict read/write</title>
+
+ <para>If the application only occasionally needs to update data (i.e. if
+ it is extremely unlikely that two transactions would try to update the
+ same item simultaneously), and strict transaction isolation is not
+ required, a <literal>nonstrict-read-write</literal> cache might be
+ appropriate. If the cache is used in a JTA environment, you must specify
+ <literal>hibernate.transaction.manager_lookup_class</literal>. In
other
+ environments, you should ensure that the transaction is completed when
+ <literal>Session.close()</literal> or
+ <literal>Session.disconnect()</literal> is called.</para>
+ </section>
+
+ <section id="performance-cache-transactional">
+ <title>Strategy: transactional</title>
+
+ <para>The <literal>transactional</literal> cache strategy
provides
+ support for fully transactional cache providers such as JBoss TreeCache.
+ Such a cache can only be used in a JTA environment and you must specify
+
<literal>hibernate.transaction.manager_lookup_class</literal>.</para>
+ </section>
+
+ <section id="performance-cache-compat-matrix">
+ <title>Cache-provider/concurrency-strategy compatibility</title>
+
+ <important>
+ <para>None of the cache providers support all of the cache concurrency
+ strategies.</para>
+ </important>
+
+ <para>The following table shows which providers are compatible with
+ which concurrency strategies.</para>
+
+ <table frame="topbot">
+ <title>Cache Concurrency Strategy Support</title>
+
+ <tgroup align="left" cols="5" colsep="1"
rowsep="1">
+ <colspec colname="c1" colwidth="1*" />
+
+ <colspec colname="c2" colwidth="1*" />
+
+ <colspec colname="c3" colwidth="1*" />
+
+ <colspec colname="c4" colwidth="1*" />
+
+ <colspec colname="c5" colwidth="1*" />
+
+ <thead>
<row>
<entry>Cache</entry>
- <entry>Provider class</entry>
- <entry>Type</entry>
- <entry>Cluster Safe</entry>
- <entry>Query Cache Supported</entry>
+
+ <entry>read-only</entry>
+
+ <entry>nonstrict-read-write</entry>
+
+ <entry>read-write</entry>
+
+ <entry>transactional</entry>
</row>
- </thead>
- <tbody>
+ </thead>
+
+ <tbody>
<row>
- <entry>Hashtable (not intended for production use)</entry>
-
<entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
- <entry>memory</entry>
- <entry> </entry>
- <entry>yes</entry>
+ <entry>Hashtable (not intended for production use)</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
</row>
+
<row>
- <entry>EHCache</entry>
-
<entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
- <entry>memory, disk</entry>
- <entry> </entry>
- <entry>yes</entry>
+ <entry>EHCache</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
</row>
+
<row>
- <entry>OSCache</entry>
-
<entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
- <entry>memory, disk</entry>
- <entry> </entry>
- <entry>yes</entry>
+ <entry>OSCache</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
</row>
+
<row>
- <entry>SwarmCache</entry>
-
<entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
- <entry>clustered (ip multicast)</entry>
- <entry>yes (clustered invalidation)</entry>
- <entry> </entry>
+ <entry>SwarmCache</entry>
+
+ <entry>yes</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
+
+ <entry></entry>
</row>
+
<row>
- <entry>JBoss Cache 1.x</entry>
-
<entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
- <entry>clustered (ip multicast), transactional</entry>
- <entry>yes (replication)</entry>
- <entry>yes (clock sync req.)</entry>
+ <entry>JBoss Cache 1.x</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
+
+ <entry></entry>
+
+ <entry>yes</entry>
</row>
+
<row>
- <entry>JBoss Cache 2</entry>
-
<entry><literal>org.hibernate.cache.jbc.JBossCacheRegionFactory</literal></entry>
- <entry>clustered (ip multicast), transactional</entry>
- <entry>yes (replication or invalidation)</entry>
- <entry>yes (clock sync req.)</entry>
+ <entry>JBoss Cache 2</entry>
+
+ <entry>yes</entry>
+
+ <entry></entry>
+
+ <entry></entry>
+
+ <entry>yes</entry>
</row>
- </tbody>
- </tgroup>
- </table>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+ </section>
- <section id="performance-cache-mapping" revision="2">
- <title>Cache mappings</title>
+ <section id="performance-sessioncache" revision="2">
+ <title>Managing the caches</title>
- <para>
- The <literal><cache></literal> element of a
class or collection mapping has the
- following form:
- </para>
+ <para>Whenever you pass an object to <literal>save()</literal>,
+ <literal>update()</literal> or
<literal>saveOrUpdate()</literal>, and
+ whenever you retrieve an object using <literal>load()</literal>,
+ <literal>get()</literal>, <literal>list()</literal>,
+ <literal>iterate()</literal> or <literal>scroll()</literal>,
that object
+ is added to the internal cache of the
<literal>Session</literal>.</para>
- <programlistingco>
- <areaspec>
- <area id="cache1" coords="2"/>
- <area id="cache2" coords="3"/>
- <area id="cache3" coords="4"/>
- </areaspec>
- <programlisting><![CDATA[<cache
- usage="transactional|read-write|nonstrict-read-write|read-only"
- region="RegionName"
- include="all|non-lazy"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="cache1">
- <para>
- <literal>usage</literal> (required) specifies the
caching strategy:
- <literal>transactional</literal>,
- <literal>read-write</literal>,
- <literal>nonstrict-read-write</literal> or
- <literal>read-only</literal>
- </para>
- </callout>
- <callout arearefs="cache2">
- <para>
- <literal>region</literal> (optional: defaults to
the class or
- collection role name): specifies the name of the second level
cache
- region
- </para>
- </callout>
- <callout arearefs="cache3">
- <para>
- <literal>include</literal> (optional: defaults to
<literal>all</literal>)
- <literal>non-lazy</literal>: specifies that
properties of the entity mapped
- with <literal>lazy="true"</literal>
cannot be cached when attribute-level
- lazy fetching is enabled
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Alternatively, you can specify
<literal><class-cache></literal> and
- <literal><collection-cache></literal> elements
in <literal>hibernate.cfg.xml</literal>.
- </para>
-
- <para>
- The <literal>usage</literal> attribute specifies a
<emphasis>cache concurrency strategy</emphasis>.
- </para>
+ <para>When <literal>flush()</literal> is subsequently called, the
state of
+ that object will be synchronized with the database. If you do not want
+ this synchronization to occur, or if you are processing a huge number of
+ objects and need to manage memory efficiently, the
+ <literal>evict()</literal> method can be used to remove the object and
its
+ collections from the first-level cache.</para>
- </section>
+ <example>
+ <title>Explcitly evicting a cached instance from the first level cache
+ using <methodname>Session.evict()</methodname></title>
- <section id="performance-cache-readonly">
- <title>Strategy: read only</title>
+ <programlisting role="JAVA">ScrollableResult cats =
sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+ Cat cat = (Cat) cats.get(0);
+ doSomethingWithACat(cat);
+ sess.evict(cat);
+}</programlisting>
+ </example>
- <para>
- If your application needs to read, but not modify, instances of a
persistent class, a
- <literal>read-only</literal> cache can be used. This is the
simplest and optimal performing
- strategy. It is even safe for use in a cluster.
- </para>
+ <para>The <literal>Session</literal> also provides a
+ <literal>contains()</literal> method to determine if an instance belongs
+ to the session cache.</para>
- <programlisting role="XML"><![CDATA[<class
name="eg.Immutable" mutable="false">
- <cache usage="read-only"/>
- ....
-</class>]]></programlisting>
+ <para>To evict all objects from the session cache, call
+ <literal>Session.clear()</literal></para>
- </section>
+ <para>For the second-level cache, there are methods defined on
+ <literal>SessionFactory</literal> for evicting the cached state of an
+ instance, entire class, collection instance or entire collection
+ role.</para>
+ <example>
+ <title>Second-level cache eviction via
+ <methodname>SessionFactoty.evict() </methodname>and
+
<methodname>SessionFacyory.evictCollection()</methodname></title>
- <section id="performance-cache-readwrite">
- <title>Strategy: read/write</title>
+ <programlisting role="JAVA">sessionFactory.evict(Cat.class, catId);
//evict a particular Cat
+sessionFactory.evict(Cat.class); //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular
collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten
collections</programlisting>
+ </example>
- <para>
- If the application needs to update data, a
<literal>read-write</literal> cache might be appropriate.
- This cache strategy should never be used if serializable transaction
isolation level is required.
- If the cache is used in a JTA environment, you must specify the property
- <literal>hibernate.transaction.manager_lookup_class</literal>
and naming a strategy for obtaining the
- JTA <literal>TransactionManager</literal>. In other
environments, you should ensure that the transaction
- is completed when <literal>Session.close()</literal> or
<literal>Session.disconnect()</literal> is called.
- If you want to use this strategy in a cluster, you should ensure that the
underlying cache implementation
- supports locking. The built-in cache providers <emphasis>do
not</emphasis> support locking.
- </para>
+ <para>The <literal>CacheMode</literal> controls how a particular
session
+ interacts with the second-level cache:</para>
- <programlisting role="XML"><![CDATA[<class
name="eg.Cat" .... >
- <cache usage="read-write"/>
- ....
- <set name="kittens" ... >
- <cache usage="read-write"/>
- ....
- </set>
-</class>]]></programlisting>
+ <itemizedlist>
+ <listitem>
+ <para><literal>CacheMode.NORMAL</literal>: will read items from
and
+ write items to the second-level cache</para>
+ </listitem>
- </section>
+ <listitem>
+ <para><literal>CacheMode.GET</literal>: will read items from
the
+ second-level cache. Do not write to the second-level cache except when
+ updating data</para>
+ </listitem>
- <section id="performance-cache-nonstrict">
- <title>Strategy: nonstrict read/write</title>
+ <listitem>
+ <para><literal>CacheMode.PUT</literal>: will write items to
the
+ second-level cache. Do not read from the second-level cache</para>
+ </listitem>
- <para>
- If the application only occasionally needs to update data (i.e. if it is
extremely unlikely that two
- transactions would try to update the same item simultaneously), and
strict transaction isolation is
- not required, a <literal>nonstrict-read-write</literal> cache
might be appropriate. If the cache is
- used in a JTA environment, you must specify
<literal>hibernate.transaction.manager_lookup_class</literal>.
- In other environments, you should ensure that the transaction is
completed when
- <literal>Session.close()</literal> or
<literal>Session.disconnect()</literal> is called.
- </para>
+ <listitem>
+ <para><literal>CacheMode.REFRESH</literal>: will write items to
the
+ second-level cache. Do not read from the second-level cache. Bypass
+ the effect of <literal>hibernate.cache.use_minimal_puts</literal>
+ forcing a refresh of the second-level cache for all items read from
+ the database</para>
+ </listitem>
+ </itemizedlist>
- </section>
+ <para>To browse the contents of a second-level or query cache region, use
+ the <literal>Statistics</literal> API:</para>
- <section id="performance-cache-transactional">
- <title>Strategy: transactional</title>
+ <example>
+ <title>Browsing the second-level cache entries via the
+ <classname>Statistics</classname> API</title>
- <para>
- The <literal>transactional</literal> cache strategy provides
support for fully transactional cache
- providers such as JBoss TreeCache. Such a cache can only be used in a JTA
environment and you must
- specify
<literal>hibernate.transaction.manager_lookup_class</literal>.
- </para>
+ <programlisting role="JAVA">Map cacheEntries =
sessionFactory.getStatistics()
+ .getSecondLevelCacheStatistics(regionName)
+ .getEntries();</programlisting>
+ </example>
- </section>
+ <para>You will need to enable statistics and, optionally, force Hibernate
+ to keep the cache entries in a more readable format:</para>
- <section id="performance-cache-compat-matrix">
- <title>Cache-provider/concurrency-strategy compatibility</title>
+ <example>
+ <title>Enabling Hibernate statistics</title>
- <important>
- <para>
- None of the cache providers support all of the cache concurrency
strategies.
- </para>
- </important>
+ <programlisting>hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true</programlisting>
+ </example>
+ </section>
- <para>
- The following table shows which providers are compatible with which
concurrency strategies.
- </para>
+ <section id="performance-querycache" revision="1">
+ <title>The Query Cache</title>
- <table frame="topbot">
- <title>Cache Concurrency Strategy Support</title>
- <tgroup cols='5' align='left' colsep='1'
rowsep='1'>
- <colspec colname='c1' colwidth="1*"/>
- <colspec colname='c2' colwidth="1*"/>
- <colspec colname='c3' colwidth="1*"/>
- <colspec colname='c4' colwidth="1*"/>
- <colspec colname='c5' colwidth="1*"/>
- <thead>
- <row>
- <entry>Cache</entry>
- <entry>read-only</entry>
- <entry>nonstrict-read-write</entry>
- <entry>read-write</entry>
- <entry>transactional</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>Hashtable (not intended for production
use)</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry> </entry>
- </row>
- <row>
- <entry>EHCache</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry> </entry>
- </row>
- <row>
- <entry>OSCache</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry> </entry>
- </row>
- <row>
- <entry>SwarmCache</entry>
- <entry>yes</entry>
- <entry>yes</entry>
- <entry> </entry>
- <entry> </entry>
- </row>
- <row>
- <entry>JBoss Cache 1.x</entry>
- <entry>yes</entry>
- <entry> </entry>
- <entry> </entry>
- <entry>yes</entry>
- </row>
- <row>
- <entry>JBoss Cache 2</entry>
- <entry>yes</entry>
- <entry> </entry>
- <entry> </entry>
- <entry>yes</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
+ <para>Query result sets can also be cached. This is only useful for
+ queries that are run frequently with the same parameters.</para>
- </section>
+ <section id="performance-querycache-enable">
+ <title>Enabling query caching</title>
- </section>
+ <para>Caching of query results introduces some overhead in terms of your
+ applications normal transactional processing. For example, if you cache
+ results of a query against Person Hibernate will need to keep track of
+ when those results should be invalidated because changes have been
+ committed against Person. That, coupled with the fact that most
+ applications simply gain no benefit from caching query results, leads
+ Hibernate to disable caching of query results by default. To use query
+ caching, you will first need to enable the query cache:</para>
- <section id="performance-sessioncache" revision="2">
- <title>Managing the caches</title>
+ <programlisting>hibernate.cache.use_query_cache true</programlisting>
- <para>
- Whenever you pass an object to <literal>save()</literal>,
<literal>update()</literal>
- or <literal>saveOrUpdate()</literal>, and whenever you retrieve
an object using
- <literal>load()</literal>, <literal>get()</literal>,
<literal>list()</literal>,
- <literal>iterate()</literal> or
<literal>scroll()</literal>, that object is added
- to the internal cache of the <literal>Session</literal>.
- </para>
- <para>
- When <literal>flush()</literal> is subsequently called, the state
of that object will
- be synchronized with the database. If you do not want this synchronization to
occur, or
- if you are processing a huge number of objects and need to manage memory
efficiently,
- the <literal>evict()</literal> method can be used to remove the
object and its collections
- from the first-level cache.
- </para>
-
- <programlisting role="JAVA"><![CDATA[ScrollableResult cats =
sess.createQuery("from Cat as cat").scroll(); //a huge result set
-while ( cats.next() ) {
- Cat cat = (Cat) cats.get(0);
- doSomethingWithACat(cat);
- sess.evict(cat);
-}]]></programlisting>
-
- <para>
- The <literal>Session</literal> also provides a
<literal>contains()</literal> method to determine
- if an instance belongs to the session cache.
- </para>
-
- <para>
- To evict all objects from the session cache, call
<literal>Session.clear()</literal>
- </para>
-
- <para>
- For the second-level cache, there are methods defined on
<literal>SessionFactory</literal> for
- evicting the cached state of an instance, entire class, collection instance
or entire collection
- role.
- </para>
-
- <programlisting
role="JAVA"><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a
particular Cat
-sessionFactory.evict(Cat.class); //evict all Cats
-sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular
collection of kittens
-sessionFactory.evictCollection("Cat.kittens"); //evict all kitten
collections]]></programlisting>
+ <para>This setting creates two new cache regions: <itemizedlist>
+ <listitem>
+
<para><classname>org.hibernate.cache.StandardQueryCache</classname>,
+ holding the cached query results</para>
+ </listitem>
- <para>
- The <literal>CacheMode</literal> controls how a particular
session interacts with the second-level
- cache:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <literal>CacheMode.NORMAL</literal>: will read items from and
write items to the second-level cache
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>CacheMode.GET</literal>: will read items from the
second-level cache. Do not write to
- the second-level cache except when updating data
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>CacheMode.PUT</literal>: will write items to the
second-level cache. Do not read from
- the second-level cache
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>CacheMode.REFRESH</literal>: will write items to the
second-level cache. Do not read from
- the second-level cache. Bypass the effect of
<literal>hibernate.cache.use_minimal_puts</literal> forcing
- a refresh of the second-level cache for all items read from the database
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- To browse the contents of a second-level or query cache region, use the
<literal>Statistics</literal>
- API:
- </para>
-
- <programlisting role="JAVA"><![CDATA[Map cacheEntries =
sessionFactory.getStatistics()
- .getSecondLevelCacheStatistics(regionName)
- .getEntries();]]></programlisting>
-
- <para>
- You will need to enable statistics and, optionally, force Hibernate to keep
the cache entries in a
- more readable format:
- </para>
-
- <programlisting><![CDATA[hibernate.generate_statistics true
-hibernate.cache.use_structured_entries true]]></programlisting>
-
+ <listitem>
+
<para><classname>org.hibernate.cache.UpdateTimestampsCache</classname>,
+ holding timestamps of the most recent updates to queryable tables.
+ These are used to validate the results as they are served from the
+ query cache.</para>
+ </listitem>
+ </itemizedlist></para>
+
+ <important>
+ <para>If you configure your underlying cache implementation to use
+ expiry or timeouts is very important that the cache timeout of the
+ underlying cache region for the UpdateTimestampsCache be set to a
+ higher value than the timeouts of any of the query caches. In fact, we
+ recommend that the the UpdateTimestampsCache region not be configured
+ for expiry at all. Note, in particular, that an LRU cache expiry
+ policy is never appropriate.</para>
+ </important>
+
+ <para>As mentioned above, most queries do not benefit from caching or
+ their results. So by default, individual queries are not cached even
+ after enabling query caching. To enable results caching for a particular
+ query, call <literal>org.hibernate.Query.setCacheable(true)</literal>.
+ This call allows the query to look for existing cache results or add its
+ results to the cache when it is executed.</para>
+
+ <note>
+ <para>The query cache does not cache the state of the actual entities
+ in the cache; it caches only identifier values and results of value
+ type. For this reaso, the query cache should always be used in
+ conjunction with the second-level cache for those entities expected to
+ be cached as part of a query result cache (just as with collection
+ caching).</para>
+ </note>
</section>
- <section id="performance-querycache" revision="1">
- <title>The Query Cache</title>
+ <section id="performance-querycache-regions">
+ <title>Query cache regions</title>
- <para>
- Query result sets can also be cached. This is only useful for queries that
are run
- frequently with the same parameters.
- </para>
+ <para>If you require fine-grained control over query cache expiration
+ policies, you can specify a named cache region for a particular query by
+ calling <literal>Query.setCacheRegion()</literal>.</para>
- <section id="performance-querycache-enable">
- <title>Enabling query caching</title>
- <para>
- Caching of query results introduces some overhead in terms of your
applications normal
- transactional processing. For example, if you cache results of a query
against Person
- Hibernate will need to keep track of when those results should be
invalidated because
- changes have been committed against Person. That, coupled with the fact
that most
- applications simply gain no benefit from caching query results, leads
Hibernate to
- disable caching of query results by default. To use query caching, you
will first
- need to enable the query cache:
- </para>
- <programlisting><![CDATA[hibernate.cache.use_query_cache
true]]></programlisting>
- <para>
- This setting creates two new cache regions:
- <itemizedlist>
- <listitem>
- <para>
-
<classname>org.hibernate.cache.StandardQueryCache</classname>, holding
- the cached query results
- </para>
- </listitem>
- <listitem>
- <para>
-
<classname>org.hibernate.cache.UpdateTimestampsCache</classname>, holding
- timestamps of the most recent updates to queryable tables.
These are used
- to validate the results as they are served from the query
cache.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <important>
- <para>
- If you configure your underlying cache implementation to use expiry
or
- timeouts is very important that the cache timeout of the underlying
- cache region for the UpdateTimestampsCache be set to a higher value
than
- the timeouts of any of the query caches. In fact, we recommend that
the
- the UpdateTimestampsCache region not be configured for expiry at all.
Note,
- in particular, that an LRU cache expiry policy is never appropriate.
- </para>
- </important>
- <para>
- As mentioned above, most queries do not benefit from caching or their
results. So by
- default, individual queries are not cached even after enabling query
caching. To enable
- results caching for a particular query, call
- <literal>org.hibernate.Query.setCacheable(true)</literal>.
This call allows the query
- to look for existing cache results or add its results to the cache when
it is executed.
- </para>
- <note>
- <para>
- The query cache does not cache the state of the actual entities in
the cache; it
- caches only identifier values and results of value type. For this
reaso, the query
- cache should always be used in conjunction with the second-level
cache for those
- entities expected to be cached as part of a query result cache (just
as with
- collection caching).
- </para>
- </note>
- </section>
-
- <section id="performance-querycache-regions">
- <title>Query cache regions</title>
- <para>
- If you require fine-grained control over query cache expiration policies,
you can
- specify a named cache region for a particular query by calling
- <literal>Query.setCacheRegion()</literal>.
- </para>
- <programlisting role="JAVA"><![CDATA[List blogs =
sess.createQuery("from Blog blog where blog.blogger = :blogger")
+ <programlisting role="JAVA">List blogs =
sess.createQuery("from Blog blog where blog.blogger = :blogger")
.setEntity("blogger", blogger)
.setMaxResults(15)
.setCacheable(true)
.setCacheRegion("frontpages")
- .list();]]></programlisting>
+ .list();</programlisting>
- <para>
- If you want to force the query cache to refresh one of its regions
(disregard any
- cached results it finds there) you can use
-
<literal>org.hibernate.Query.setCacheMode(CacheMode.REFRESH)</literal>. In
conjunction
- with the region you have defined for the given query, Hibernate will
selectively force
- the results cached in that particular region to be refreshed. This is
particularly useful
- in cases where underlying data may have been updated via a separate
process and is a far more
- efficient alternative to bulk eviction of the region via
-
<literal>org.hibernate.SessionFactory.evictQueries()</literal>.
- </para>
- </section>
+ <para>If you want to force the query cache to refresh one of its regions
+ (disregard any cached results it finds there) you can use
+
<literal>org.hibernate.Query.setCacheMode(CacheMode.REFRESH)</literal>.
+ In conjunction with the region you have defined for the given query,
+ Hibernate will selectively force the results cached in that particular
+ region to be refreshed. This is particularly useful in cases where
+ underlying data may have been updated via a separate process and is a
+ far more efficient alternative to bulk eviction of the region via
+
<literal>org.hibernate.SessionFactory.evictQueries()</literal>.</para>
</section>
+ </section>
- <section id="performance-collections">
- <title>Understanding Collection performance</title>
+ <section id="performance-collections">
+ <title>Understanding Collection performance</title>
- <para>
- In the previous sections we have covered collections and their applications.
- In this section we explore some more issues in relation to
- collections at runtime.
- </para>
+ <para>In the previous sections we have covered collections and their
+ applications. In this section we explore some more issues in relation to
+ collections at runtime.</para>
- <section id="performance-collections-taxonomy">
- <title>Taxonomy</title>
+ <section id="performance-collections-taxonomy">
+ <title>Taxonomy</title>
- <para>Hibernate defines three basic kinds of collections:</para>
+ <para>Hibernate defines three basic kinds of collections:</para>
- <itemizedlist>
- <listitem>
- <para>collections of values</para>
- </listitem>
- <listitem>
- <para>one-to-many associations</para>
- </listitem>
- <listitem>
- <para>many-to-many associations</para>
- </listitem>
- </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para>collections of values</para>
+ </listitem>
- <para>
- This classification distinguishes the various table and foreign key
- relationships but does not tell us quite everything we need to know
- about the relational model. To fully understand the relational structure
- and performance characteristics, we must also consider the structure of
- the primary key that is used by Hibernate to update or delete collection
- rows. This suggests the following classification:
- </para>
+ <listitem>
+ <para>one-to-many associations</para>
+ </listitem>
- <itemizedlist>
- <listitem>
- <para>indexed collections</para>
- </listitem>
- <listitem>
- <para>sets</para>
- </listitem>
- <listitem>
- <para>bags</para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>many-to-many associations</para>
+ </listitem>
+ </itemizedlist>
- <para>
- All indexed collections (maps, lists, and arrays) have a primary key
consisting
- of the <literal><key></literal> and
<literal><index></literal>
- columns. In this case, collection updates are extremely efficient.
- The primary key can be efficiently indexed and a particular row can be
efficiently
- located when Hibernate tries to update or delete it.
- </para>
-
- <para>
- Sets have a primary key consisting of
<literal><key></literal> and element
- columns. This can be less efficient for some types of collection element,
particularly
- composite elements or large text or binary fields, as the database may
not be able to index
- a complex primary key as efficiently. However, for one-to-many or
many-to-many
- associations, particularly in the case of synthetic identifiers, it is
likely to be just
- as efficient. If you want <literal>SchemaExport</literal> to
actually create
- the primary key of a <literal><set></literal>,
you must declare all columns
- as <literal>not-null="true"</literal>.
- </para>
+ <para>This classification distinguishes the various table and foreign
+ key relationships but does not tell us quite everything we need to know
+ about the relational model. To fully understand the relational structure
+ and performance characteristics, we must also consider the structure of
+ the primary key that is used by Hibernate to update or delete collection
+ rows. This suggests the following classification:</para>
- <para>
- <literal><idbag></literal> mappings define a
surrogate key, so they are
- efficient to update. In fact, they are the best case.
- </para>
-
- <para>
- Bags are the worst case since they permit duplicate element values and,
as they have no
- index column, no primary key can be defined. Hibernate has no way of
distinguishing
- between duplicate rows. Hibernate resolves this problem by completely
removing
- in a single <literal>DELETE</literal> and recreating the
collection whenever it
- changes. This can be inefficient.
- </para>
+ <itemizedlist>
+ <listitem>
+ <para>indexed collections</para>
+ </listitem>
- <para>
- For a one-to-many association, the "primary key" may not be the
physical
- primary key of the database table. Even in this case, the above
classification
- is still useful. It reflects how Hibernate "locates" individual
rows of the
- collection.
- </para>
+ <listitem>
+ <para>sets</para>
+ </listitem>
- </section>
+ <listitem>
+ <para>bags</para>
+ </listitem>
+ </itemizedlist>
- <section id="performance-collections-mostefficientupdate">
- <title>Lists, maps, idbags and sets are the most efficient collections
to update</title>
+ <para>All indexed collections (maps, lists, and arrays) have a primary
+ key consisting of the <literal><key></literal> and
+ <literal><index></literal> columns. In this case,
collection
+ updates are extremely efficient. The primary key can be efficiently
+ indexed and a particular row can be efficiently located when Hibernate
+ tries to update or delete it.</para>
- <para>
- From the discussion above, it should be clear that indexed collections
- and sets allow the most efficient operation in terms of adding,
- removing and updating elements.
- </para>
+ <para>Sets have a primary key consisting of
+ <literal><key></literal> and element columns. This can be
less
+ efficient for some types of collection element, particularly composite
+ elements or large text or binary fields, as the database may not be able
+ to index a complex primary key as efficiently. However, for one-to-many
+ or many-to-many associations, particularly in the case of synthetic
+ identifiers, it is likely to be just as efficient. If you want
+ <literal>SchemaExport</literal> to actually create the primary key of
a
+ <literal><set></literal>, you must declare all columns
as
+ <literal>not-null="true"</literal>.</para>
- <para>
- There is, arguably, one more advantage that indexed collections have over
sets for
- many-to-many associations or collections of values. Because of the
structure of a
- <literal>Set</literal>, Hibernate does not
<literal>UPDATE</literal> a row when
- an element is "changed". Changes to a
<literal>Set</literal> always work via
- <literal>INSERT</literal> and
<literal>DELETE</literal> of individual rows. Once
- again, this consideration does not apply to one-to-many associations.
- </para>
+ <para><literal><idbag></literal> mappings define a
surrogate key,
+ so they are efficient to update. In fact, they are the best case.</para>
- <para>
- After observing that arrays cannot be lazy, you can conclude that lists,
maps and
- idbags are the most performant (non-inverse) collection types, with sets
not far
- behind. You can expect sets to be the most common kind of collection in
Hibernate
- applications. This is because the "set" semantics are most
natural in the relational
- model.
- </para>
+ <para>Bags are the worst case since they permit duplicate element values
+ and, as they have no index column, no primary key can be defined.
+ Hibernate has no way of distinguishing between duplicate rows. Hibernate
+ resolves this problem by completely removing in a single
+ <literal>DELETE</literal> and recreating the collection whenever it
+ changes. This can be inefficient.</para>
- <para>
- However, in well-designed Hibernate domain models, most collections
- are in fact one-to-many associations with
<literal>inverse="true"</literal>. For these
- associations, the update is handled by the many-to-one end of the
association, and so
- considerations of collection update performance simply do not apply.
- </para>
+ <para>For a one-to-many association, the "primary key" may not be
the
+ physical primary key of the database table. Even in this case, the above
+ classification is still useful. It reflects how Hibernate "locates"
+ individual rows of the collection.</para>
+ </section>
- </section>
+ <section id="performance-collections-mostefficientupdate">
+ <title>Lists, maps, idbags and sets are the most efficient collections
+ to update</title>
- <section id="performance-collections-mostefficentinverse">
- <title>Bags and lists are the most efficient inverse
collections</title>
+ <para>From the discussion above, it should be clear that indexed
+ collections and sets allow the most efficient operation in terms of
+ adding, removing and updating elements.</para>
- <para>
- There is a particular case, however, in which bags, and also lists,
- are much more performant than sets. For a collection with
<literal>inverse="true"</literal>,
- the standard bidirectional one-to-many relationship idiom, for example,
we can add elements
- to a bag or list without needing to initialize (fetch) the bag elements.
This is because, unlike a <literal>set</literal>,
- <literal>Collection.add()</literal> or
<literal>Collection.addAll()</literal> must always
- return true for a bag or <literal>List</literal>. This can
- make the following common code much faster:
- </para>
+ <para>There is, arguably, one more advantage that indexed collections
+ have over sets for many-to-many associations or collections of values.
+ Because of the structure of a <literal>Set</literal>, Hibernate does
not
+ <literal>UPDATE</literal> a row when an element is "changed".
Changes to
+ a <literal>Set</literal> always work via
<literal>INSERT</literal> and
+ <literal>DELETE</literal> of individual rows. Once again, this
+ consideration does not apply to one-to-many associations.</para>
- <programlisting role="JAVA"><![CDATA[Parent p = (Parent)
sess.load(Parent.class, id);
+ <para>After observing that arrays cannot be lazy, you can conclude that
+ lists, maps and idbags are the most performant (non-inverse) collection
+ types, with sets not far behind. You can expect sets to be the most
+ common kind of collection in Hibernate applications. This is because the
+ "set" semantics are most natural in the relational model.</para>
+
+ <para>However, in well-designed Hibernate domain models, most
+ collections are in fact one-to-many associations with
+ <literal>inverse="true"</literal>. For these associations,
the update is
+ handled by the many-to-one end of the association, and so considerations
+ of collection update performance simply do not apply.</para>
+ </section>
+
+ <section id="performance-collections-mostefficentinverse">
+ <title>Bags and lists are the most efficient inverse
collections</title>
+
+ <para>There is a particular case, however, in which bags, and also
+ lists, are much more performant than sets. For a collection with
+ <literal>inverse="true"</literal>, the standard
bidirectional
+ one-to-many relationship idiom, for example, we can add elements to a
+ bag or list without needing to initialize (fetch) the bag elements. This
+ is because, unlike a <literal>set</literal>,
+ <literal>Collection.add()</literal> or
+ <literal>Collection.addAll()</literal> must always return true for a
bag
+ or <literal>List</literal>. This can make the following common code
much
+ faster:</para>
+
+ <programlisting role="JAVA">Parent p = (Parent)
sess.load(Parent.class, id);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c); //no need to fetch the collection!
-sess.flush();]]></programlisting>
+sess.flush();</programlisting>
+ </section>
- </section>
+ <section id="performance-collections-oneshotdelete">
+ <title>One shot delete</title>
- <section id="performance-collections-oneshotdelete">
- <title>One shot delete</title>
+ <para>Deleting collection elements one by one can sometimes be extremely
+ inefficient. Hibernate knows not to do that in the case of an
+ newly-empty collection (if you called <literal>list.clear()</literal>,
+ for example). In this case, Hibernate will issue a single
+ <literal>DELETE</literal>.</para>
- <para>
- Deleting collection elements one by one can sometimes be extremely
inefficient. Hibernate
- knows not to do that in the case of an newly-empty collection
- (if you called <literal>list.clear()</literal>, for example).
In this case, Hibernate will
- issue a single <literal>DELETE</literal>.
- </para>
+ <para>Suppose you added a single element to a collection of size twenty
+ and then remove two elements. Hibernate will issue one
+ <literal>INSERT</literal> statement and two
<literal>DELETE</literal>
+ statements, unless the collection is a bag. This is certainly
+ desirable.</para>
- <para>
- Suppose you added a single element to a collection of size twenty and
then remove two elements.
- Hibernate will issue one <literal>INSERT</literal> statement
and two <literal>DELETE</literal>
- statements, unless the collection is a bag. This is certainly desirable.
- </para>
+ <para>However, suppose that we remove eighteen elements, leaving two and
+ then add thee new elements. There are two possible ways to
+ proceed</para>
- <para>
- However, suppose that we remove eighteen elements, leaving two and then
add thee new elements.
- There are two possible ways to proceed
- </para>
+ <itemizedlist>
+ <listitem>
+ <para>delete eighteen rows one by one and then insert three
+ rows</para>
+ </listitem>
- <itemizedlist>
- <listitem>
- <para>delete eighteen rows one by one and then insert three
rows</para>
- </listitem>
- <listitem>
- <para>remove the whole collection in one SQL
<literal>DELETE</literal> and insert
- all five current elements one by one</para>
- </listitem>
- </itemizedlist>
+ <listitem>
+ <para>remove the whole collection in one SQL
+ <literal>DELETE</literal> and insert all five current elements one
+ by one</para>
+ </listitem>
+ </itemizedlist>
- <para>
- Hibernate cannot know that the second option is probably quicker.
- It would probably be undesirable for Hibernate to be that intuitive as
such behavior might
- confuse database triggers, etc.
- </para>
+ <para>Hibernate cannot know that the second option is probably quicker.
+ It would probably be undesirable for Hibernate to be that intuitive as
+ such behavior might confuse database triggers, etc.</para>
- <para>
- Fortunately, you can force this behavior (i.e. the second strategy) at
any time by discarding
- (i.e. dereferencing) the original collection and returning a newly
instantiated collection with
- all the current elements.
- </para>
-
- <para>
- One-shot-delete does not apply to collections mapped
<literal>inverse="true"</literal>.
- </para>
+ <para>Fortunately, you can force this behavior (i.e. the second
+ strategy) at any time by discarding (i.e. dereferencing) the original
+ collection and returning a newly instantiated collection with all the
+ current elements.</para>
- </section>
-
+ <para>One-shot-delete does not apply to collections mapped
+ <literal>inverse="true"</literal>.</para>
</section>
+ </section>
- <section id="performance-monitoring" revision="1">
- <title>Monitoring performance</title>
+ <section id="performance-monitoring" revision="1">
+ <title>Monitoring performance</title>
- <para>
- Optimization is not much use without monitoring and access to performance
numbers.
- Hibernate provides a full range of figures about its internal operations.
- Statistics in Hibernate are available per
<literal>SessionFactory</literal>.
- </para>
+ <para>Optimization is not much use without monitoring and access to
+ performance numbers. Hibernate provides a full range of figures about its
+ internal operations. Statistics in Hibernate are available per
+ <literal>SessionFactory</literal>.</para>
- <section id="performance-monitoring-sf" revision="2">
- <title>Monitoring a SessionFactory</title>
+ <section id="performance-monitoring-sf" revision="2">
+ <title>Monitoring a SessionFactory</title>
- <para>
- You can access <literal>SessionFactory</literal> metrics in
two ways.
- Your first option is to call
<literal>sessionFactory.getStatistics()</literal> and
- read or display the <literal>Statistics</literal> yourself.
- </para>
+ <para>You can access <literal>SessionFactory</literal> metrics in
two
+ ways. Your first option is to call
+ <literal>sessionFactory.getStatistics()</literal> and read or display
+ the <literal>Statistics</literal> yourself.</para>
- <para>
- Hibernate can also use JMX to publish metrics if you enable the
- <literal>StatisticsService</literal> MBean. You can enable a
single MBean for all your
- <literal>SessionFactory</literal> or one per factory. See the
following code for
- minimalistic configuration examples:
- </para>
+ <para>Hibernate can also use JMX to publish metrics if you enable the
+ <literal>StatisticsService</literal> MBean. You can enable a single
+ MBean for all your <literal>SessionFactory</literal> or one per
factory.
+ See the following code for minimalistic configuration examples:</para>
- <programlisting role="JAVA"><![CDATA[// MBean service
registration for a specific SessionFactory
+ <programlisting role="JAVA">// MBean service registration for a
specific SessionFactory
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp");
@@ -1436,93 +1537,86 @@
StatisticsService stats = new StatisticsService(); // MBean implementation
stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
-server.registerMBean(stats, on); // Register the Mbean on the
server]]></programlisting>
+server.registerMBean(stats, on); // Register the Mbean on the
server</programlisting>
-
-<programlisting role="JAVA"><![CDATA[// MBean service registration for
all SessionFactory's
+ <programlisting role="JAVA">// MBean service registration for all
SessionFactory's
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "all");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); // MBean implementation
-server.registerMBean(stats, on); // Register the MBean on the
server]]></programlisting>
+server.registerMBean(stats, on); // Register the MBean on the
server</programlisting>
- <para>
- You can activate and deactivate the monitoring for a
<literal>SessionFactory</literal>:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- at configuration time, set
<literal>hibernate.generate_statistics</literal> to
<literal>false</literal>
- </para>
- </listitem>
- </itemizedlist>
- <itemizedlist>
- <listitem>
- <para>
- at runtime:
<literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
- or
<literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
- </para>
- </listitem>
- </itemizedlist>
+ <para>You can activate and deactivate the monitoring for a
+ <literal>SessionFactory</literal>:</para>
- <para>
- Statistics can be reset programmatically using the
<literal>clear()</literal> method.
- A summary can be sent to a logger (info level) using the
<literal>logSummary()</literal>
- method.
- </para>
+ <itemizedlist>
+ <listitem>
+ <para>at configuration time, set
+ <literal>hibernate.generate_statistics</literal> to
+ <literal>false</literal></para>
+ </listitem>
+ </itemizedlist>
- </section>
+ <itemizedlist>
+ <listitem>
+ <para>at runtime:
+ <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
or
+
<literal>hibernateStatsBean.setStatisticsEnabled(true)</literal></para>
+ </listitem>
+ </itemizedlist>
- <section id="performance-monitoring-metrics"
revision="1">
- <title>Metrics</title>
+ <para>Statistics can be reset programmatically using the
+ <literal>clear()</literal> method. A summary can be sent to a logger
+ (info level) using the <literal>logSummary()</literal>
method.</para>
+ </section>
- <para>
- Hibernate provides a number of metrics, from basic information to more
specialized information
- that is only relevant in certain scenarios. All available counters are
described in the
- <literal>Statistics</literal> interface API, in three
categories:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- Metrics related to the general
<literal>Session</literal> usage, such as
- number of open sessions, retrieved JDBC connections, etc.
- </para>
- </listitem>
- <listitem>
- <para>
- Metrics related to the entities, collections, queries, and caches
as a
- whole (aka global metrics).
- </para>
- </listitem>
- <listitem>
- <para>
- Detailed metrics related to a particular entity, collection,
query or
- cache region.
- </para>
- </listitem>
- </itemizedlist>
+ <section id="performance-monitoring-metrics" revision="1">
+ <title>Metrics</title>
- <para>
- For example, you can check the cache hit, miss, and put ratio of
entities, collections
- and queries, and the average time a query needs. Be aware that the number
of milliseconds
- is subject to approximation in Java. Hibernate is tied to the JVM
precision and on some
- platforms this might only be accurate to 10 seconds.
- </para>
+ <para>Hibernate provides a number of metrics, from basic information to
+ more specialized information that is only relevant in certain scenarios.
+ All available counters are described in the
+ <literal>Statistics</literal> interface API, in three
categories:</para>
- <para>
- Simple getters are used to access the global metrics (i.e. not tied to a
particular entity,
- collection, cache region, etc.). You can access the metrics of a
particular entity, collection
- or cache region through its name, and through its HQL or SQL
representation for queries. Please
- refer to the <literal>Statistics</literal>,
<literal>EntityStatistics</literal>,
- <literal>CollectionStatistics</literal>,
<literal>SecondLevelCacheStatistics</literal>,
- and <literal>QueryStatistics</literal> API Javadoc for more
information. The following
- code is a simple example:
- </para>
+ <itemizedlist>
+ <listitem>
+ <para>Metrics related to the general
<literal>Session</literal>
+ usage, such as number of open sessions, retrieved JDBC connections,
+ etc.</para>
+ </listitem>
- <programlisting role="JAVA"><![CDATA[Statistics stats =
HibernateUtil.sessionFactory.getStatistics();
+ <listitem>
+ <para>Metrics related to the entities, collections, queries, and
+ caches as a whole (aka global metrics).</para>
+ </listitem>
+ <listitem>
+ <para>Detailed metrics related to a particular entity, collection,
+ query or cache region.</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>For example, you can check the cache hit, miss, and put ratio of
+ entities, collections and queries, and the average time a query needs.
+ Be aware that the number of milliseconds is subject to approximation in
+ Java. Hibernate is tied to the JVM precision and on some platforms this
+ might only be accurate to 10 seconds.</para>
+
+ <para>Simple getters are used to access the global metrics (i.e. not
+ tied to a particular entity, collection, cache region, etc.). You can
+ access the metrics of a particular entity, collection or cache region
+ through its name, and through its HQL or SQL representation for queries.
+ Please refer to the <literal>Statistics</literal>,
+ <literal>EntityStatistics</literal>,
+ <literal>CollectionStatistics</literal>,
+ <literal>SecondLevelCacheStatistics</literal>, and
+ <literal>QueryStatistics</literal> API Javadoc for more information.
The
+ following code is a simple example:</para>
+
+ <programlisting role="JAVA">Statistics stats =
HibernateUtil.sessionFactory.getStatistics();
+
double queryCacheHitCount = stats.getQueryCacheHitCount();
double queryCacheMissCount = stats.getQueryCacheMissCount();
double queryCacheHitRatio =
@@ -1536,18 +1630,14 @@
entityStats.getInsertCount()
+ entityStats.getUpdateCount()
+ entityStats.getDeleteCount();
-log.info(Cat.class.getName() + " changed " + changes + "times"
);]]></programlisting>
+log.info(Cat.class.getName() + " changed " + changes + "times"
);</programlisting>
- <para>
- You can work on all entities, collections, queries and region caches, by
retrieving
- the list of names of entities, collections, queries and region caches
using the
- following methods: <literal>getQueries()</literal>,
<literal>getEntityNames()</literal>,
- <literal>getCollectionRoleNames()</literal>, and
- <literal>getSecondLevelCacheRegionNames()</literal>.
- </para>
-
- </section>
-
+ <para>You can work on all entities, collections, queries and region
+ caches, by retrieving the list of names of entities, collections,
+ queries and region caches using the following methods:
+ <literal>getQueries()</literal>,
<literal>getEntityNames()</literal>,
+ <literal>getCollectionRoleNames()</literal>, and
+ <literal>getSecondLevelCacheRegionNames()</literal>.</para>
</section>
-
+ </section>
</chapter>