Hibernate Framework : ORM Tool :: Hibernate Cache Management
- Hibernate Cache Intro
- Understanding Second Level Cache
- First-level Cache
- Second-level Cache Complete Example
- Download Examples
Hibernate Cache Intro |
Understanding Hibernate Cache Architecture
Accessing a database is an expensive operation, even for a simple query. The request has to be sent (usually over the network) to the server. The database server may have to compile the SQL into a query plan. The query plan has to be run and is limited largely by disk performance.
Most good databases will cache the results of a query if it is run multiple times, eliminating the disk I/O and query compilation time; but this will be of limited value if there are large numbers of clients making substantially different requests. Even if the cache generally holds the results, the time taken to transmit the information across the network is often the larger part of the delay.
The natural and obvious answer is to have a cache at the client end of the database connection. This is not a feature provided or supported by JDBC directly, but Hibernate provides one cache (the first-level, or L1, cache) through which all requests must pass. A second-level cache is optional and configurable.
Hibernate has dual level cache architecture.
A Cache helps to keep the current database state (local copy of the data) available to the application, whenever a lookup is performed or lazy initialization is needed.
The hibernate cache architecture allows you to develop thread safe application by providing a unique set of persistent instances for each session.
It provides a continuous data access by not allowing any thread to enter into the wait state through out an application.
Two level of cache available in hibernate ORM
- First-level Cache
- Second-level Cache
Hibernate Cache Level Architecture
Figure1
Figure2
First-level Cache |
First Level Cache
The first-level cache is always associated with the session object. It is active for the user who handles a database transaction or an application transaction. The first-level cache is mandatory and can not be turned off. It also maintains the object identity inside a transaction and helps in avoiding database traffic.
Benefit of First-level Cache
- Allows processing of repeated request for the same instance in a particular session.
- Allows to implement O/R mapping, which maps a database table to a POJO class so that any changes made to that POJO object are updated to the database table.
- Allows a transaction to view the changes made in other transactions.
In the first-level cache architecture, the flush() method is used to synchronize the object the database. In order to manage memory and avoid synchronization, the evict() method can be used. This method removes the object and its collections from the first-level cache. the Session.clear() method completely removes all the objects from the session cache.
Second-level Cache |
Second-level Cache
- Some entities however are shared by many different use cases and are barely changed. You can cache these in what is called the second level cache.
- In the second-level cache, the caching strategies and cache providers are to be used correctly as per your requirement of a hibernate application. The usage depends on the ratio of reads to writes, the size of the database table, and database tables that are shared with other external applications. Therefore, the second level cache is configurable at the granularity of an individual class of collection role. The second-level cache can be used for both immutable and mutable data.
Elements available in second-level cache architecture
- Cache Strategy
- Query Cache
- Cache Provider
- Cache Strategy
The cache concurrency strategy used by default can be set with the hibernate.cache.default_cache_concurrency_strategy property:
- read-only : used for data that is read frequently but never updated.
- read-write : used when your data is read as well as updated.
- nonstrict-read-write : used when an application rarely needs to update data and read more and more data from a transaction. it is used when two transaction are not allowed to modify data simultaneously.
- transactional: Specifies a fully transactional cache that may be used only in a JTA environment.
for Example
Using Annotation
Entity @Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }
Note:- usage: the given cache concurrency strategy (NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
Using hbm file
<hibernate-mapping>
<class name="Account" table="Account">
<cache usage="read-write"/>
</class>
</hibernate-mapping>
Query Cache
The Query Cache is used to store the result set of a query that is executed against a database table. In order to enable the query cache, the hibernate.cache.use_query_cache property is set to true in the hibernate configuration file.
hibernate-configuration
<hibernate-configuration>
<session-factory>
<property name="cache.use_query_cache">true</property>
<property name="cache.use_second_level_cache">true</property>
</session-factory>
</hibernate-configuration>
Second Level Cache Complete Examples |
Project Hierarchy
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">jdbc:mysql://localhost:3306/javaskoolDB</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="pfname">javaskoolMySQLDriver</property>
<property name="connection.password">admin</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<property name="cache.use_query_cache">true</property>
<property name="cache.use_second_level_cache">true</property>
<mapping resource="com/javaskool/item.hbm.xml" />
</session-factory>
</hibernate-configuration>
ehcache.xml
<?xml version="1.0"?>
<ehcache>
<defaultCache maxElementsInMemory="100" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="200" />
<cache name="com.javaskool.Item" maxElementsInMemory="100" eternal="false" timeToIdleSeconds="4" timeToLiveSeconds="200" />
</ehcache>
<!--
In ehcache.xml,
Actually <defaultCache
/> will reflects to all the pojo classes in our application,
and we can also assign the ehcache values to specified pojo class
by <cache name=your pojo class name ..... />
if eternal=true then we should not write timeToIdealSeconds,
timeToLiveSeconds, hibernate will take care about those values
So if you want to give values manually better eternal=false always,
so that we can assign values into timeToIdealSeconds, timeToLiveSeconds manually,
and play with second level cache
timeToIdealSeconds=seconds means, if the object in the global cache is ideal,
means not using by any other class or object
then it will be waited for some time we specified and deleted from the global cache
if time is exceeds more than timeToIdealSeconds value
timeToLiveSeconds=seconds means, the other Session or class using this object
or not, i mean may be it is using by other sessions or may not, what ever
the situation might be, once it competed the time specified timeToLiveSeconds,
then it will be removed from the global cache by hibernate
-->
item.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.javaskool">
<class name="Item" table="ItemTab">
<cache usage="read-only" />
<id name="ItemId" column="itemId">
<generator class="increment"></generator>
</id>
<property name="itemName" column="itemName"></property>
<property name="qty" column="qty"></property>
</class>
</hibernate-mapping>
<!--
<cache usage="read-only" />
or it can be
1. read-only
2. read-write
3. transactional
4. nonstrict-read-write
-->
Item.java
package com.javaskool;
//Item Bean
public class Item {
//Item Property
private Integer itemId;
private String itemName;
private Integer qty;
//getter and setter Methods
public Integer getItemId() {
return itemId;
}
public void setItemId(Integer itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Integer getQty() {
return qty;
}
public void setQty(Integer qty) {
this.qty = qty;
}
}
TestDrive.java
package com.javaskool;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class TestDrive {
public static void main(String[] args)
{
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session sess1 = sfactory.openSession();
Object obj=sess1.load(Item.class,101);
Item i1=(Item)obj;
System.out.println("Loaded Item name is : "+i1.getItemName());
System.out.println("Item Object Loaded successfully.....!!");
sess1.close();
System.out.println("---------------------------");
System.out.println("Just Waiting.....for 5 sec.");
try{
Thread.sleep(5000);
}
catch (Exception e) {}
System.out.println("5 Seconds Over!!");
Session sess2 = sfactory.openSession();
Object obj2=sess2.load(Item.class,101);
Item i2=(Item)obj2;
System.out.println("Loaded Item name is : "+i2.getItemName());
System.out.println("Item Object Loaded from Database successfully!!");
sess2.close();
Session sess3 = sfactory.openSession();
Object obj3=sess3.load(Item.class,new Integer(101));
Item i3=(Item)obj3;
System.out.println("Loaded Item name is : "+i3.getItemName());
System.out.println("Item Object Loaded from global cache successfully!!");
sess3.close();
sfactory.close();
}
}
/*
* we opened sess1 and loaded object and closed sess1,
this time object will be loaded from the database as its the first time
Then we have been waited for 5 seconds, but in our ehcache.xml
we have given timeToIdleSeconds="4" , i mean after 4 seconds object
will be removed from the global cache And again in TestDrive.java,
we opened second sess2 and loaded the object, this time hibernate will
loads the object from the database, and closed the sess2
Immediately we opened sess3 and loaded the object, this time hibernate
will loads the object form the global session not from the database
*/
Hibernate Generated Query and Result
Loaded Item name is : Laptop
Item Object Loaded successfully.....!!
------------------------------
Just Waiting.....for 5 sec.
5 Seconds Over!!
Loaded Item name is : Laptop
Item Object Loaded from Database successfully!!
Loaded Item name is : Laptop
Item Object Loaded from global cache successfully!!
Table and Record in the project
mysql>CREATE TABLE `itemtab` (
`itemId` int(11) NOT NULL AUTO_INCREMENT,
`itemName` varchar(20) DEFAULT NULL,
`qty` int(11) DEFAULT NULL,
PRIMARY KEY (`itemId`)
) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=latin1;
mysql> select * from itemTab;
+--------+----------+------+
| itemId | itemName | qty |
+--------+----------+------+
| 101 | Laptop | 90 |
| 102 | Monitor | 190 |
| 103 | Mouse | 390 |
+--------+----------+------+
3 rows in set (2.12 sec)
Download Examples |
Click the below Link to download complete Example
Recent Comments