In my experience while developing applications I have come across situations where the performance of the application goes down due to heavy traffic to database. Hibernate is one ORM which helps overcome such difficult situations with its caching feature. In this article I shall discuss about this feature in detail.
How Hibernate Caching works?
In web applications using Hibernate, cache actually stores the data already loaded from the database. This helps reduce traffic between our application and the database. Most of the times the application fetches the data from the cache. Whenever a new data is needed, the database will be accessed. As the time needed to access the database is more compared to accessing the cache, traffic will be reduced between the application and the database. Here the cache stores only the data related to current running application. In order to do that, the cache must be cleared whenever the application is changing. Let us see how this is done in the sections below:
Hibernate uses following caches for objects:
Figure 1: First Level and Second Level Caching
- First-level cache: It always associates with the Session object. It is a mandatory cache through which all requests must pass. Hibernate uses this cache by default. If you issue multiple updates to an object, Hibernate tries to delay doing the update as long as possible to reduce the number of update SQL statements issued. It updates the transaction only at the end of the transaction.
- Second-level cache: It always associates with the Session Factory object. This is an optional cache. Second level cache is created in session factory scope and is available to be used in all sessions which are created using that particular session factory. The
- second-level cache can be configured on a per-class and per-collection basis and mainly responsible for caching objects across sessions. It means that once session factory is closed, all cache associated with it dies and cache manager also closed down.
- Query Cache: Query Cache is used to cache the results of a query. When the query cache is turned on, the results of the query are stored against the combination query and parameters. Every time the query is fired the cache manager checks for the combination of parameters and query. If the results are found in the cache, they are returned, otherwise a database transaction is initiated.
- Any third-party cache can be used with Hibernate. An org.hibernate.cache.CacheProvider interface is provided, which must be implemented to provide Hibernate with a handle to the cache implementation.
A concurrency strategy is a mediator which responsible for storing items of data in the cache and retrieving them from the cache. If you are going to enable a second-level cache, you will have to decide, for each persistent class and collection, which cache concurrency strategy to use.
- Useful for data that is read frequently but never updated.
- It is Simple.
- Best performer among the all.
- It is safe for using in a cluster.
Here is an example for using the read-only cache strategy.
Listing 1: read-only cache strategy
<hibernate-mapping> <class name="Student" table="STUDENT"> <meta attribute="class-description"> This class contains the STUDENT detail. </meta> <cache usage="read-only"/> .... </class> .......... </hibernate-mapping>
The usage="read-only" attribute tells Hibernate to use a read-only concurrency strategy for the defined cache.
- Used when our data needs to be updated.
- It’s having more overhead than read-only caches.
- When Session.close() or Session.disconnect() is called the transaction should be completed in an environment where JTA is no used.
- It is never used if serializable transaction isolation level is required.
- In a JTA environment, for obtaining the JTA TransactionManager we must specify the property hibernate.transaction.manager_lookup_class.
- To use it in a cluster the cache implementation must support locking.
Here is an example for using the read-write cache stringategy.
Listing 2: read-write cache stringategy
<hibernate-mapping> <class name="Student" table="STUDENT"> <meta attribute="class-description"> This class contains the STUDENT detail. </meta> <cache usage="read-write"/> .... </class> .......... </hibernate-mapping>
The usage="read-write" attribute tells Hibernate to use a read-write concurrency strategy for the defined cache.Nonstrict read-write
- Needed if the application needs to update data rarely.
- we must specify hibernate.transaction.manager_lookup_class to use this in a JTA environment .
- The transaction is completed when Session.close() or Session.disconnect() is called in other environments (except JTA) .
Here is an example for using the nonstrict read-write cache strategy.
Listing 3: nonstrict read-write cache strategy
<class name="abc.xyz" .... > <cache usage=" nonstrict-read-write"/> …. </class>
Use this strategy for read-mostly data where it is critical to prevent stale data in concurrent transactions, in the rare case of an update.
Cache Implementations using Providers:
Now that we understand the concurrency strategies; for our cache candidate classes we need to pick a cache provider. Hibernate forces you to choose a single cache provider for the whole application. Every cache provider is not compatible with every concurrency strategy. Hibernate supports following open-source cache implementations out-of-the-box: EHCache (Easy Hibernate Cache), OSCache (Open Symphony Cache), Swarm Cache, and JBoss Tree Cache.
Let's see each of these in details:EHCache (Easy Hibernate Cache) from Hibernate framework
- It is fast, lightweight and easy-to-use.
- Supports read-only and read/write caching.
- Supports memory-based and disk-based caching.
- Does not support clustering.
- It is a powerful and flexible package
- Supports read-only and read/write caching.
- Supports memory- based and disk-based caching.
- Provides basic support for clustering via either JavaGroups or JMS.
- is a cluster-based caching.
- supports read-only or nonstrict read/write caching .
- appropriate for applications those have more read operations than write operations.
- is a powerful, replicated(synchronous or asynchronous) and transactional cache.
- useful when we need a true transaction-capable caching architecture.
The following compatibility table will help you choose an appropriate combination.
|Cache Provider||Read-Only||Nonstrict read-only||Read-Write||Transactional|
In this article we saw what is hibernate caching, types and concurrent strategies. We also understood the available cache providers and how to choose them. Thats all for now!