Oct 9, 2009

Hibernate is a high-performance, object/relational persistence and query service, but it won't solve all the performance issues without a little help. Hence we use the concept of Caching here. Caching is mainly used for optimizing database applications and is designed to reduce the traffic between our application and the database by conserving data already loaded from database. This article will give you the overview of Hibernate Caching mechanisms.

By implementing Caching, the application will work with the data in the cache most of the time. Whenever there is a request for data that is not cached, the database will be contacted. So obviously the access time and 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 time to time whenever the applications are changing.

Hibernate uses two different caches for objects: first-level cache and second-level cache

Hibernate uses first level cache within a single transaction boundary and also uses this by default.

This is mainly used to reduce the number of SQL queries it needs to generate within a given transaction. For Example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE at the end, containing all the modifications.

It keeps loaded objects at the session factory level across the transaction boundaries.

These objects are available to the whole application, not just to the user running the query. This way, each time a query returns an object that is already loaded in the cache; one or more database transactions potentially are avoided.

The second-level cache holds on to the 'data' for all properties and associations (and collections if requested) for individual entities that are marked to be cached.

It can be used if we need to cache actual query results, rather than just persistent objects.

It does not cache the state of the actual entities in the result set; it caches only identifier values and results of value type. So the query cache should always be used in conjunction with the second-level cache.

Hibernate comes with a number of built-in integrations with open-source cache providers. Each cache provides different capacities in terms of performance, memory use, and configuration possibilities. Some of them are listed below.

SwarmCache is a simple cluster-based caching solution based on JavaGroups.

It uses IP multicast to efficiently communicate with any number of hosts on a LAN

Provider class: org.hibernate.cache.SwarmCacheProvider

Supports read-only or nonstrict read/write caching

It is specifically designed for use by clustered, database-driven web applications. Such applications typically have many more read operations than write operations, which allows SwarmCache to deliver the greatest performance gains

Configuration of a particular caching mechanism is specified in the hibernate.cfg.xml file as in the below example.

<hibernate-configuration>

<session-factory>

...

<property name="hibernate.cache.provider_class">

org.hibernate.cache.EHCacheProvider

</property>

...

</session-factory>

</hibernate-configuration>

The name in <property> tag must be hibernate.cache.provider_class for activating second-level cache. We can use hibernate.cache.use_second_level_cache property, which allows you to activate and deactivate the second-level cache. By default, the second-level cache is activated and uses the EHCache.

It is very important to select the specific Caching strategy after selecting the particular cache implementation. Because none of the cache providers support all of the cache concurrency strategies. The following four caching strategies are available:

Read-only: This strategy is useful for data that is read frequently but never updated. This is by far the simplest and best-performing cache strategy. Here is an example for using the read-only cache strategy.

<class name="abc.mutable” mutable="true ">

<cache usage="read-only"/>

....

</class>

Read/write: Read/write caches may be appropriate if your data needs to be updated. They carry more overhead than read-only caches. In non-JTA environments, each transaction should be completed when Session.close () or Session.disconnect () is called. Here is an example for using the read-write cache strategy.

<class name="abc.xyz" .... >

<cache usage="read-write"/>

….

<set name="yuv" ... >

<cache usage="read-write"/>

….

</set>

</class>

Nonstrict read/write: This strategy does not guarantee that two transactions won't simultaneously modify the same data. Therefore, it may be most appropriate for data that is read often but only occasionally modified. An example for NonStrict read-write cache strategy,

<class name="abc.xyz" .... >

<cache usage=" nonstrict-read-write"/>

……

</class>

Transactional: This is a fully transactional cache that may be used only in a JTA environment.

The caching strategy options available for different cache implementations are described in the following table.

Hibernate has a flexible and powerful way of implementing caching mechanisms which will be very helpful in improving the performance of web applications which incorporate heavy database traffics. It should be implemented using an incremental, test-driven approach. When done correctly, a small amount of well executed caching can boost our applications to their maximum capacities.