The purpose of a cache is to reduce access to the database.
There are two kinds of caches in a Hibernate application. The Hibernate session is the first one, the second one can be used optionally.
The Hibernate session is a transactional cache, i.e. it shows the changes a user has already flushed within an open transaction. As a session belongs to a unique user, theses changes are not propagated to other sessions. I remind you that a session is not thread-safe, do not share it across threads!
The second level cache is shared across a Java virtual machine instance or, if you use clustering, it can even be shared across multiple servers across a network. All your sessions share this cache. The second level cache normally contains only committed data. (except for transaction caches, where you can configure the isolation level)
A cache does not reference your objects, so changes to the objects will not destroy the cache. A cache resembles more a Map having a combination of id and class as key and an array as value, where the array holds all the field values.
Key | Field 1 | Field 2 | Field 3 |
---|---|---|---|
de.laliluna.Developer#680 | Peter | 123 | 12.22 |
de.laliluna.Developer#674 | Karl | 1234 | 77.55 |
This is of course a simplification. A cache does also handle information about the creation time, last access time, change time and some very effective search algorithms.
A cache holds objects to prevent database queries. A cache is not aware of changes which bypass Hibernate for example queries issued by JDBC or from other non Java applications.
Choosing the cache mode
There are four cache modes available.
Standard cache
The standard cache is filled when you load any data with methods like
The cache is used when Hibernate has to create an instance from a given id. This is done when you use for example
You can configure the size of the cache and when items should expire. Expiring is useful when you update data with other applications from time to time but you can accept a delay during which the user sees stale data.
You do not have to set a timeout when your application is the only one accessing the database.
You can evict objects from the cache using the session factory (not the session itself). It provides methods like evict and others to deal with data in the cache.
Using the cache
Configure the cache in your hibernate.cfg.xml or in the hibernate.properties.
<property name="cache.provider_class"> org.hibernate.cache.EhCacheProvider </property>
Add a configuration file for your selected cache. You can find more detailed information about each cache in the following chapters. Here is a short example.
<cache name="myCache" maxElementsInMemory="6000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="true" />
Add the cache tag to your class and to all relations you want to cache. You can specify a cache region to use a special configuration. For example I used the myCache configuration but you can also leave out the region definition in order to use the default configuration.
<class name="Developer" table="tdeveloper"> <cache usage="read-only" region="myCache" /> <list name="computers" cascade="all"> <cache usage="read-only" region="myCache" /> <key column="developer_id" not-null="true"></key> <list-index column="listindex"></list-index> <one-to-many class="Computer" /> </list>
That’s it.
Query cache
A query cache contains the object ids found by a query. The query and the parameters are used as key. As a consequence a query cache is only useful when you have queries with the same parameters issued regularly. When a table is updated, all cached queries touching the table are evicted from the cache as they are considered to be outdated.
To sum up, a query cache is useful when you have a lot of identical selects compared to the number of updates. Typical applications are content management systems, Internet forums with a lot of read access etc.
To use the query cache you must do at least the following:
In the hibernate.properties or hibernate.cfg.xml add the property
<property name="hibernate.cache.use_query_cache">true</property>
In your query set CacheAble to true
List result = session.createQuery( "from Computer c where c.name like ? order by c.name desc, c.id asc") .setString(0,param) .setCacheable(true).list();
You can also specify a special cache region used for your query using setCacheRegion
List result = session.createQuery( "from Computer c where c.name like ? order by c.name desc, c.id asc") .setString(0,param) .setCacheable(true).setCacheRegion(“myQueryCache”).list();
That’s it.
As opposed to the table in the Hibernate reference all of the following cache providers support query caching.
Test all caches
We provided an example application named TestCache. It will output access times to the data.
In order to use the test, generate test data first. Adapt the hibernate.cfg.xml to suit your database and uncomment the setupTest method in the class TestMain to generate random data entries.
Have a look at the class TestMain to comment or uncomment the tests you want to run and to specify which mapping to load. We have mappings for all supported cache modes. A cache provider does not support every mode.
You can configure the number of threads for running two kinds of tests. The first uses session.get to randomly select entries. The other test queries data with random parameters. Both tests log how the access times are changing by the time when your cache is filled. Run a no cache test to compare the results.
In the hibernate.cfg.xml you can configure the cache provider. Configuration files for any of the following caches can be found in the project as well. Read in the following descriptions to learn more about needed libraries.
EH cache is the standard cache for Hibernate. It can be used as a distributed cache or as cache for JSP content. Detailed information can be found on the EH Cache website at
http://ehcache.sourceforge.net/documentation/
The configuration is done in the ehcache.xml file:
<ehcache> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: user.home - User's home directory user.dir - User's current working directory java.io.tmpdir - Default temp file path --> <diskStore path="java.io.tmpdir"/> <cache name="myCache" maxElementsInMemory="6000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" /> <cache name="net.sf.hibernate.cache.StandardQueryCache" maxElementsInMemory="20" eternal="false" timeToLiveSeconds="240" overflowToDisk="false"/> <cache name="net.sf.hibernate.cache.UpdateTimestampsCache" maxElementsInMemory="5000" eternal="true" overflowToDisk="false"/> <defaultCache maxElementsInMemory="7000" eternal="false" timeToIdleSeconds="180" timeToLiveSeconds="180" overflowToDisk="false" /> </ehcache>
Cache provider in the hibernate.cfg.xml:
<property name="cache.provider_class"> org.hibernate.cache.EhCacheProvider </property>
Needed libraries:
Supported cache modes:
OS Cache can also be used as distributed cache or as cache for JSP content. Clustering using JMS and jgroups is supported. Detailed information can be found at http://www.opensymphony.com/oscache/.
Cache provider:
<property name="cache.provider_class"> org.hibernate.cache.OSCacheProvider </property>
Needed libraries:
Supported cache modes:
The swarm cache can be used as distributed cash as well. It uses jgroups for the clustering. Further information can be found at http://swarmcache.sourceforge.net/.
Cache provider:
<property name="cache.provider_class"> org.hibernate.cache.SwarmCacheProvider </property>
Needed libraries:
Supported cache modes:
JBoss Treecache
JBoss is the only transactional cache in our list. It supports clustering as well. Further information can be found at http://www.jboss.org/products/jbosscache
You may consider using the treecache if you use Hibernate on JBoss.
Cache provider:
<property name="cache.provider_class"> org.hibernate.cache.TreeCacheProvider </property>
Needed libraries to run in a java application:
For a web application deployed on a JBoss application server you will probably not need any of these libraries as they are already contained in a typical JBoss installation.
Supported cache modes: