alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (performance.xml)

This example Hibernate source code file (performance.xml) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

cat, cat, for, hibernate, hibernate, if, in, java, java, mbean, this, this, xml, you

The Hibernate performance.xml source code

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors.  All third-party contributions are
  ~ distributed under license by Red Hat Middleware LLC.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;
]>
<chapter id="performance">
  <title>Improving performance

  <section id="performance-fetching" revision="2">
    <title>Fetching strategies

    <para>Hibernate uses a fetching strategy 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
    query.</para>

    <para>Hibernate3 defines the following fetching strategies:

    <itemizedlist>
      <listitem>
        <para>Join fetching: Hibernate retrieves the
        associated instance or collection in the same
        <literal>SELECT, using an OUTER
        JOIN</literal>.
      </listitem>

      <listitem>
        <para>Select fetching: a second
        <literal>SELECT is used to retrieve the associated entity or
        collection. Unless you explicitly disable lazy fetching by specifying
        <literal>lazy="false", this second select will only be
        executed when you access the association.</para>
      </listitem>

      <listitem>
        <para>Subselect fetching: a second
        <literal>SELECT 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", this second select will only be
        executed when you access the association.</para>
      </listitem>

      <listitem>
        <para>Batch fetching: an optimization strategy
        for select fetching. Hibernate retrieves a batch of entity instances
        or collections in a single <literal>SELECT by specifying a
        list of primary or foreign keys.</para>
      </listitem>
    </itemizedlist>

    <para>Hibernate also distinguishes between:

    <itemizedlist>
      <listitem>
        <para>Immediate fetching: an association,
        collection or attribute is fetched immediately when the owner is
        loaded.</para>
      </listitem>

      <listitem>
        <para>Lazy collection fetching: a collection is
        fetched when the application invokes an operation upon that
        collection. This is the default for collections.</para>
      </listitem>

      <listitem>
        <para>"Extra-lazy" collection fetching:
        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>Proxy fetching: a single-valued association
        is fetched when a method other than the identifier getter is invoked
        upon the associated object.</para>
      </listitem>

      <listitem>
        <para>"No-proxy" fetching: 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>Lazy attribute fetching: 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: when is
    the association fetched and <emphasis>how is it fetched. It is
    important that you do not confuse them. We use <literal>fetch to
    tune performance. We can use <literal>lazy 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

      <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 hibernate.default_batch_fetch_size,
      Hibernate will use the batch fetch optimization for lazy fetching. This
      optimization can also be enabled at a more granular level.</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")
    .setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!</programlisting>

      <para>Since the permissions collection was not initialized when the
      <literal>Session 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" 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

      <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"/>

      <para>The fetch strategy defined in the mapping
      document affects:</para>

      <itemizedlist>
        <listitem>
          <para>retrieval via get() or
          <literal>load()
        </listitem>

        <listitem>
          <para>retrieval that happens implicitly when an association is
          navigated</para>
        </listitem>

        <listitem>
          <para>Criteria queries
        </listitem>

        <listitem>
          <para>HQL queries if subselect 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 in HQL. This tells
      Hibernate to fetch the association eagerly in the first select, using an
      outer join. In the <literal>Criteria query API, you would use
      <literal>setFetchMode(FetchMode.JOIN).

      <para>If you want to change the fetching strategy used by
      <literal>get() or load(), you can use a
      <literal>Criteria query. For example:

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

      <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

      <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 and one-to-one
      associations.</para>

      <para>The mapping file may declare an interface to use as the proxy
      interface for that class, with the <literal>proxy 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>There are potential problems to note when extending this approach
      to polymorphic classes.For example:</para>

      <programlisting role="XML"><class name="Cat" proxy="Cat">
    ......
    <subclass name="DomesticCat">
        .....
    </subclass>
</class></programlisting>

      <para>Firstly, instances of Cat will never be
      castable to <literal>DomesticCat, even if the underlying
      instance is an instance of <literal>DomesticCat:

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

      <para>Secondly, it is possible to break proxy
      <literal>==:

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

      <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">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 final
      class or a class with any <literal>final methods.

      <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 implements the interface
      <literal>Cat and DomesticCatImpl implements
      the interface <literal>DomesticCat. For example:

      <programlisting role="XML"><class name="CatImpl" proxy="Cat">
    ......
    <subclass name="DomesticCatImpl" proxy="DomesticCat">
        .....
    </subclass>
</class></programlisting>

      <para>Then proxies for instances of Cat and
      <literal>DomesticCat can be returned by
      <literal>load() or iterate().

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

      <note>
        <title>Note

        <para>list() 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, not
      <literal>CatImpl.

      <para>Certain operations do not require proxy
      initialization:</para>

      <itemizedlist spacing="compact">
        <listitem>
          <para>equals(): if the persistent class does not
          override <literal>equals()
        </listitem>

        <listitem>
          <para>hashCode(): if the persistent class does
          not override <literal>hashCode()
        </listitem>

        <listitem>
          <para>The identifier getter method
        </listitem>
      </itemizedlist>

      <para>Hibernate will detect persistent classes that override
      <literal>equals() or hashCode().

      <para>By choosing lazy="no-proxy" instead of the
      default <literal>lazy="proxy", you can avoid problems
      associated with typecasting. However, buildtime bytecode instrumentation
      is required, and all operations will result in immediate proxy
      initialization.</para>
    </section>

    <section id="performance-fetching-initialization" revision="1">
      <title>Initializing collections and proxies

      <para>A LazyInitializationException will be thrown by
      Hibernate if an uninitialized collection or proxy is accessed outside of
      the scope of the <literal>Session, i.e., when the entity
      owning the collection or having the reference to the proxy is in the
      detached state.</para>

      <para>Sometimes a proxy or collection needs to be initialized before
      closing the <literal>Session. You can force initialization by
      calling <literal>cat.getSex() or
      <literal>cat.getKittens().size(), for example. However, this
      can be confusing to readers of the code and it is not convenient for
      generic code.</para>

      <para>The static methods Hibernate.initialize() and
      <literal>Hibernate.isInitialized(), provide the application
      with a convenient way of working with lazily initialized collections or
      proxies. <literal>Hibernate.initialize(cat) will force the
      initialization of a proxy, <literal>cat, as long as its
      <literal>Session is still open. Hibernate.initialize(
      cat.getKittens() )</literal> has a similar effect for the collection of
      kittens.</para>

      <para>Another option is to keep the Session 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 is open when a collection
      is initialized. There are two basic ways to deal with this issue:</para>

      <itemizedlist>
        <listitem>
          <para>In a web-based application, a servlet filter can be used to
          close the <literal>Session only at the end of a user
          request, once the rendering of the view is complete (the
          <emphasis>Open Session in View 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 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() 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 clause or a
          <literal>FetchMode.JOIN in Criteria.
          This is usually easier if you adopt the <emphasis>Command
          pattern instead of a <emphasis>Session Facade.
        </listitem>

        <listitem>
          <para>You can also attach a previously loaded object to a new
          <literal>Session with merge() or
          <literal>lock() before accessing uninitialized collections
          or other proxies. Hibernate does not, and certainly
          <emphasis>should not, do this automatically since it
          would introduce impromptu transaction semantics.</para>
        </listitem>
      </itemizedlist>

      <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>You can use a collection filter to get the size of a collection
      without initializing it:</para>

      <programlisting role="JAVA">( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()

      <para>The createFilter() method is also used to
      efficiently retrieve subsets of a collection without needing to
      initialize the whole collection:</para>

      <programlisting role="JAVA">s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();
    </section>

    <section id="performance-fetching-batch">
      <title>Using batch fetching

      <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 instances loaded in a Session,
      and each <literal>Cat has a reference to its
      <literal>owner, a Person. The
      <literal>Person class is mapped with a proxy,
      <literal>lazy="true". If you now iterate through all cats and
      call <literal>getOwner() on each, Hibernate will, by default,
      execute 25 <literal>SELECT statements to retrieve the proxied
      owners. You can tune this behavior by specifying a
      <literal>batch-size in the mapping of
      <literal>Person:

      <programlisting role="XML"><class name="Person" batch-size="10">...</class>

      <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 has a lazy collection of
      <literal>Cats, and 10 persons are currently loaded in the
      <literal>Session, iterating through all persons will generate
      10 <literal>SELECTs, one for every call to
      <literal>getCats(). If you enable batch fetching for the
      <literal>cats collection in the mapping of
      <literal>Person, Hibernate can pre-fetch collections:

      <programlisting role="XML"><class name="Person">
    <set name="cats" batch-size="3">
        ...
    </set>
</class></programlisting>

      <para>With a batch-size of 3, Hibernate will load 3,
      3, 3, 1 collections in four <literal>SELECTs. Again, the value
      of the attribute depends on the expected number of uninitialized
      collections in a particular <literal>Session.

      <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 or a materialized
      path</emphasis> might be a better option for read-mostly trees.
    </section>

    <section id="performance-fetching-subselect">
      <title>Using subselect fetching

      <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 -->
    </section>

    <section id="performance-fetching-profiles">
      <title>Fetch profiles

      <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 but enabled,
      by name, on the <interfacename>org.hibernate.Session.
      Once enabled on a <interfacename>org.hibernate.Session,
      the fetch profile will be in affect for that
      <interfacename>org.hibernate.Session until it is
      explicitly disabled.</para>

      <para>So what does that mean? Well lets explain that by way of an
      example which show the different available approaches to configure a
      fetch profile:</para>

      <example>
        <title>Specifying a fetch profile using
        <classname>@FetchProfile

        <programlisting role="XML">@Entity
@FetchProfile(name = "customer-with-orders", fetchOverrides = {
   @FetchProfile.FetchOverride(entity = Customer.class, association = "orders", mode = FetchMode.JOIN)
})
public class Customer {
   @Id
   @GeneratedValue
   private long id;

   private String name;

   private long customerNumber;

   @OneToMany
   private Set<Order> orders;

   // standard getter/setter
   ...
}</programlisting>
      </example>

      <example>
        <title>Specifying a fetch profile using
        <literal><fetch-profile> outside
        <literal><class> node

        <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">
        ...
    </class>
    <fetch-profile name="customer-with-orders">
        <fetch entity="Customer" association="orders" style="join"/>
    </fetch-profile>
</hibernate-mapping>
</programlisting>
      </example>

      <example>
        <title>Specifying a fetch profile using
        <literal><fetch-profile> inside
        <literal><class> node

        <programlisting role="XML"><hibernate-mapping>
    <class name="Customer">
        ...
        <set name="orders" inverse="true">
            <key column="cust_id"/>
            <one-to-many class="Order"/>
        </set>
        <fetch-profile name="customer-with-orders">
            <fetch association="orders" style="join"/>
        </fetch-profile>
    </class>
    <class name="Order">
        ...
    </class>
</hibernate-mapping>
</programlisting>
      </example>

      <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. The following
      code will load both the customer <emphasis>andtheir
      orders:</para>

      <example>
        <title>Activating a fetch profile for a given
        <classname>Session

        <programlisting role="JAVA">Session session = ...;
session.enableFetchProfile( "customer-with-orders" );  // name matches from mapping
Customer customer = (Customer) session.get( Customer.class, customerId );
</programlisting>
      </example>

      <note>
        <para>@FetchProfile definitions are global and
        it does not matter on which class you place them. You can place the
        <classname>@FetchProfile annotation either onto a class or
        package (package-info.java). In order to define multiple fetch
        profiles for the same class or package
        <classname>@FetchProfiles can be used.
      </note>

      <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-3414">HHH-3414</ulink>
      for details.</para>
    </section>

    <section id="performance-fetching-lazyproperties">
      <title>Using lazy property fetching

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

      <para>To enable lazy property loading, set the lazy
      attribute on your particular property mappings:</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>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>

      <para>For bytecode instrumentation, use the following Ant task:

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

    <instrument verbose="true">
        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
            <include name="*.class"/>
        </fileset>
    </instrument>
</target></programlisting>

      <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 in HQL.
    </section>
  </section>

  <section id="performance-cache" revision="1">
    <title>The Second Level Cache

    <para>A Hibernate Session is a transaction-level cache
    of persistent data. It is possible to configure a cluster or JVM-level
    (<literal>SessionFactory-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.spi.CacheProvider using the property
    <literal>hibernate.cache.provider_class. 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

      <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>Provider class

            <entry>Type

            <entry>Cluster Safe

            <entry>Query Cache Supported
          </row>
        </thead>

        <tbody>
          <row>
            <entry>ConcurrentHashMap (only for testing purpose, in hibernate-testing module)

            <entry>org.hibernate.testing.cache.CachingRegionFactory

            <entry>memory

            <entry>

            <entry>yes
          </row>

          <row>
            <entry>EHCache

            <entry>org.hibernate.cache.ehcache.EhCacheRegionFactory

            <entry>memory, disk, transactional, clustered

            <entry>yes

            <entry>yes
          </row>

<!--          

            <entry>org.hibernate.cache.OSCacheProvider

            <entry>memory, disk

            <entry>

            <entry>yes
          </row>

          <row>
            <entry>SwarmCache

            <entry>org.hibernate.cache.SwarmCacheProvider

            <entry>clustered (ip multicast)

            <entry>yes (clustered invalidation)

            <entry>
          </row>

          <row>
            <entry>JBoss Cache 1.x

            <entry>org.hibernate.cache.TreeCacheProvider

            <entry>clustered (ip multicast), transactional

            <entry>yes (replication)

            <entry>yes (clock sync req.)
          </row>

          <row>
            <entry>JBoss Cache 2

            <entry>org.hibernate.cache.jbc.JBossCacheRegionFactory

            <entry>clustered (ip multicast), transactional

            <entry>yes (replication or invalidation)

            <entry>yes (clock sync req.)
          </row> -->
          <row>
            <entry>Infinispan

            <entry>org.hibernate.cache.infinispan.InfinispanRegionFactory

            <entry>clustered (ip multicast), transactional

            <entry>yes (replication or invalidation)

            <entry>yes (clock sync req.)
          </row>
        </tbody>
      </tgroup>
    </table>

    <section id="performance-cache-mapping" revision="2">
      <title>Cache mappings

      <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 element in your
      <filename>persistence.xml file or by using the
      <literal>javax.persistence.sharedCache.mode property in your
      configuration. The following values are possible:</para>

      <itemizedlist>
        <listitem>
          <para>ENABLE_SELECTIVE (Default and recommended
          value): entities are not cached unless explicitly marked as
          cacheable.</para>
        </listitem>

        <listitem>
          <para>DISABLE_SELECTIVE: entities are cached
          unless explicitly marked as not cacheable.</para>
        </listitem>

        <listitem>
          <para>ALL: all entities are always cached even if
          marked as non cacheable.</para>
        </listitem>

        <listitem>
          <para>NONE: 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
      configuration property. The values for this property are:</para>

      <itemizedlist>
        <listitem>
          <para>read-only
        </listitem>

        <listitem>
          <para>read-write
        </listitem>

        <listitem>
          <para>nonstrict-read-write
        </listitem>

        <listitem>
          <para>transactional
        </listitem>
      </itemizedlist>

      <note>
        <para>It is recommended to define the cache concurrency strategy per
        entity rather than using a global one. Use the
        <classname>@org.hibernate.annotations.Cache annotation for
        that.</para>
      </note>

      <example id="example-cache-concurrency-with-cache-annotation">
        <title>Definition of cache concurrency strategy via
        <classname>@Cache

        <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 annotation on the collection
      property.</para>

      <example>
        <title>Caching collections using annotations

        <programlisting language="JAVA" role="JAVA">@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>shows
      the<literal> @org.hibernate.annotations.Cache 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>@Cache 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>include (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> 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 <cache> 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>usage (required) specifies the caching
              strategy: <literal>transactional,
              <literal>read-write,
              <literal>nonstrict-read-write or
              <literal>read-only
            </callout>

            <callout arearefs="cache2">
              <para>region (optional: defaults to the class
              or collection role name): specifies the name of the second level
              cache region</para>
            </callout>

            <callout arearefs="cache3">
              <para>include (optional: defaults to
              <literal>all) non-lazy: specifies
              that properties of the entity mapped with
              <literal>lazy="true" cannot be cached when
              attribute-level lazy fetching is enabled</para>
            </callout>
          </calloutlist>
        </programlistingco>
      </example>

      <para>Alternatively to <cache>, you can use
      <literal><class-cache> and
      <literal><collection-cache> elements in
      <literal>hibernate.cfg.xml.

      <para>Let's now have a closer look at the different usage
      strategies</para>
    </section>

    <section id="performance-cache-readonly">
      <title>Strategy: read only

      <para>If your application needs to read, but not modify, instances of a
      persistent class, a <literal>read-only 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

      <para>If the application needs to update data, a
      <literal>read-write 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 and naming
      a strategy for obtaining the JTA <literal>TransactionManager.
      In other environments, you should ensure that the transaction is
      completed when <literal>Session.close() or
      <literal>Session.disconnect() 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 support locking.
    </section>

    <section id="performance-cache-nonstrict">
      <title>Strategy: nonstrict read/write

      <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 cache might be
      appropriate. If the cache is used in a JTA environment, you must specify
      <literal>hibernate.transaction.manager_lookup_class. In other
      environments, you should ensure that the transaction is completed when
      <literal>Session.close() or
      <literal>Session.disconnect() is called.
    </section>

    <section id="performance-cache-transactional">
      <title>Strategy: transactional

      <para>The transactional 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.
    </section>

    <section id="performance-cache-compat-matrix">
      <title>Cache-provider/concurrency-strategy compatibility

      <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

        <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>read-only

              <entry>nonstrict-read-write

              <entry>read-write

              <entry>transactional
            </row>
          </thead>

          <tbody>
            <row>
              <entry>ConcurrentHashMap (not intended for production use)

              <entry>yes

              <entry>yes

              <entry>yes

              <entry>
            </row>

            <row>
              <entry>EHCache

              <entry>yes

              <entry>yes

              <entry>yes

              <entry>yes
            </row>

 <!--           

              <entry>yes

              <entry>yes

              <entry>yes

              <entry>
            </row>

            <row>
              <entry>SwarmCache

              <entry>yes

              <entry>yes

              <entry>

              <entry>
            </row>

            <row>
              <entry>JBoss Cache 1.x

              <entry>yes

              <entry>

              <entry>

              <entry>yes
            </row>

            <row>
              <entry>JBoss Cache 2

              <entry>yes

              <entry>

              <entry>

              <entry>yes
            </row> -->
            <row>
              <entry>Infinispan

              <entry>yes

              <entry>

              <entry>

              <entry>yes
            </row>
          </tbody>
        </tgroup>
      </table>
    </section>
  </section>

  <section id="performance-sessioncache" revision="2">
    <title>Managing the caches

    <para>Whenever you pass an object to save(),
    <literal>update() or saveOrUpdate(), and
    whenever you retrieve an object using <literal>load(),
    <literal>get(), list(),
    <literal>iterate() or scroll(), that object
    is added to the internal cache of the <literal>Session.

    <para>When flush() 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() method can be used to remove the object and its
    collections from the first-level cache.</para>

    <example>
      <title>Explcitly evicting a cached instance from the first level cache
      using <methodname>Session.evict()

      <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>The Session also provides a
    <literal>contains() 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()

    <para>For the second-level cache, there are methods defined on
    <literal>SessionFactory 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() and
      <methodname>SessionFacyory.evictCollection()

      <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>The CacheMode controls how a particular session
    interacts with the second-level cache:</para>

    <itemizedlist>
      <listitem>
        <para>CacheMode.NORMAL: will read items from and
        write items to the second-level cache</para>
      </listitem>

      <listitem>
        <para>CacheMode.GET: will read items from the
        second-level cache. Do not write to the second-level cache except when
        updating data</para>
      </listitem>

      <listitem>
        <para>CacheMode.PUT: will write items to the
        second-level cache. Do not read from the second-level cache</para>
      </listitem>

      <listitem>
        <para>CacheMode.REFRESH: 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
        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 API:

    <example>
      <title>Browsing the second-level cache entries via the
      <classname>Statistics API

      <programlisting role="JAVA">Map cacheEntries = sessionFactory.getStatistics()
        .getSecondLevelCacheStatistics(regionName)
        .getEntries();</programlisting>
    </example>

    <para>You will need to enable statistics and, optionally, force Hibernate
    to keep the cache entries in a more readable format:</para>

    <example>
      <title>Enabling Hibernate statistics

      <programlisting>hibernate.generate_statistics true
hibernate.cache.use_structured_entries true</programlisting>
    </example>
  </section>

  <section id="performance-querycache" revision="1">
    <title>The Query Cache

    <para>Query result sets can also be cached. This is only useful for
    queries that are run frequently with the same parameters.</para>

    <section id="performance-querycache-enable">
      <title>Enabling query caching

      <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>hibernate.cache.use_query_cache true

      <para>This setting creates two new cache regions: 
          <listitem>
            <para>org.hibernate.cache.internal.StandardQueryCache,
            holding the cached query results</para>
          </listitem>

          <listitem>
            <para>org.hibernate.cache.spi.UpdateTimestampsCache,
            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>

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

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

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

      <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).
      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().
    </section>
  </section>

  <section id="performance-collections">
    <title>Understanding Collection performance

    <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

      <para>Hibernate defines three basic kinds of collections:

      <itemizedlist>
        <listitem>
          <para>collections of values
        </listitem>

        <listitem>
          <para>one-to-many associations
        </listitem>

        <listitem>
          <para>many-to-many associations
        </listitem>
      </itemizedlist>

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

      <itemizedlist>
        <listitem>
          <para>indexed collections
        </listitem>

        <listitem>
          <para>sets
        </listitem>

        <listitem>
          <para>bags
        </listitem>
      </itemizedlist>

      <para>All indexed collections (maps, lists, and arrays) have a primary
      key consisting of the <literal><key> and
      <literal><index> 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> 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 to actually create the primary key of a
      <literal><set>, you must declare all columns as
      <literal>not-null="true".

      <para><idbag> 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 and recreating the collection whenever it
      changes. This can be inefficient.</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 id="performance-collections-mostefficientupdate">
      <title>Lists, maps, idbags and sets are the most efficient collections
      to update</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, 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, Hibernate does not
      <literal>UPDATE a row when an element is "changed". Changes to
      a <literal>Set always work via INSERT and
      <literal>DELETE of individual rows. Once again, this
      consideration does not apply to one-to-many associations.</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>However, in well-designed Hibernate domain models, most
      collections are in fact one-to-many associations with
      <literal>inverse="true". 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

      <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", 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>Collection.add() or
      <literal>Collection.addAll() must always return true for a bag
      or <literal>List. 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>
    </section>

    <section id="performance-collections-oneshotdelete">
      <title>One shot delete

      <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(),
      for example). In this case, Hibernate will issue a single
      <literal>DELETE.

      <para>Suppose you added a single element to a collection of size twenty
      and then remove two elements. Hibernate will issue one
      <literal>INSERT statement and two DELETE
      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>

      <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 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>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".
    </section>
  </section>

  <section id="performance-monitoring" revision="1">
    <title>Monitoring performance

    <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.

    <section id="performance-monitoring-sf" revision="2">
      <title>Monitoring a SessionFactory

      <para>You can access SessionFactory metrics in two
      ways. Your first option is to call
      <literal>sessionFactory.getStatistics() and read or display
      the <literal>Statistics yourself.

      <para>Hibernate can also use JMX to publish metrics if you enable the
      <literal>StatisticsService MBean. You can enable a single
      MBean for all your <literal>SessionFactory or one per factory.
      See the following code for minimalistic configuration examples:</para>

      <programlisting role="JAVA">// MBean service registration for a specific SessionFactory
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name

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>

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

      <para>You can activate and deactivate the monitoring for a
      <literal>SessionFactory:

      <itemizedlist>
        <listitem>
          <para>at configuration time, set
          <literal>hibernate.generate_statistics to
          <literal>false
        </listitem>
      </itemizedlist>

      <itemizedlist>
        <listitem>
          <para>at runtime:
          <literal>sf.getStatistics().setStatisticsEnabled(true) or
          <literal>hibernateStatsBean.setStatisticsEnabled(true)
        </listitem>
      </itemizedlist>

      <para>Statistics can be reset programmatically using the
      <literal>clear() method. A summary can be sent to a logger
      (info level) using the <literal>logSummary() method.
    </section>

    <section id="performance-monitoring-metrics" revision="1">
      <title>Metrics

      <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 interface API, in three categories:

      <itemizedlist>
        <listitem>
          <para>Metrics related to the general Session
          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>

      <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>EntityStatistics,
      <literal>CollectionStatistics,
      <literal>SecondLevelCacheStatistics, and
      <literal>QueryStatistics 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 =
  queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);

log.info("Query Hit ratio:" + queryCacheHitRatio);

EntityStatistics entityStats =
  stats.getEntityStatistics( Cat.class.getName() );
long changes =
        entityStats.getInsertCount()
        + entityStats.getUpdateCount()
        + entityStats.getDeleteCount();
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(), getEntityNames(),
      <literal>getCollectionRoleNames(), and
      <literal>getSecondLevelCacheRegionNames().
    </section>
  </section>
</chapter>

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate performance.xml source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.