OSCache is a Java framework developed by OpenSymphony that makes it easy to cache content in Web applications. With hibernate, it can be configured to act as second level cache.
In my previous post, we learned about configuring EhCache with hibernate, which is default second level cache in hibernate. In this post, I am taking the example of configuring OSCache with hibernate.
Sections in this post: Runtime dependencies Hibernate configuration In memory cache example Physical cache example
Runtime dependencies
I have used Maven to manage the project dependencies, and the necessary additions in pom.xml files are:
<repositories> <repository> <id>repository.jboss.org-public</id> <name>JBoss.org Maven repository</name> <url>https://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> <!-- OSCache dependencies --> <dependency> <groupId>opensymphony</groupId> <artifactId>oscache</artifactId> <version>2.4.1</version> </dependency> <dependency> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> <version>1.1</version> </dependency>
If you are not using maven then add corresponding jar files in your project build path.
Hibernate configuration
The only change for having OSCache configured in your project, you have to make in your hibernate configuration file hibernate.cfg.xml file:
<!-- Cache provider class --> <property name="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
In memory cache example
This is default implementation and you will get it if not configured the physical cache properties. Let’s see the example test code:
try { //Open the hibernate session Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); //fetch the department entity from database first time DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); //fetch the department entity again; Fetched from first level cache department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); //Let's close the session session.getTransaction().commit(); session.close(); //Try to get department in new session Session anotherSession = HibernateUtil.getSessionFactory().openSession(); anotherSession.beginTransaction(); //Here entity is already in second level cache so no database query will be hit department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); anotherSession.getTransaction().commit(); anotherSession.close(); } finally { System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount()); //Prints 1 System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount()); //Prints 1 HibernateUtil.shutdown(); } Output in console: Hibernate: insert into DEPARTMENT (NAME) values (?) Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=? Human Resource Human Resource Human Resource 1 1
You will get this output again and again because everytime hibernate is shut down, memory is flushed and second level cache is built on next run again.
Physical cache example
If you have a very large cache to build then it is good idea to build it in file system (e.g. C drive in windows). It will prevent the hibernate to build the cache on every time application is restarted. Also, second level cache fetch rules still applies.
To enable physical cache, download the oscache.properties file and uncomment following lines:
cache.memory=false cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener cache.path=c:/temp/cache cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache
Let’s see the example test code:
try { //Open the hibernate session Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); //fetch the department entity from database first time DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); //fetch the department entity again; Fetched from first level cache department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); //Let's close the session session.getTransaction().commit(); session.close(); //Try to get department in new session Session anotherSession = HibernateUtil.getSessionFactory().openSession(); anotherSession.beginTransaction(); //Here entity is already in second level cache so no database query will be hit department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1)); System.out.println(department.getName()); anotherSession.getTransaction().commit(); anotherSession.close(); } finally { System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount()); //Prints 1 System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount()); //Prints 1 HibernateUtil.shutdown(); } Output in console: Hibernate: insert into DEPARTMENT (NAME) values (?) Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=? Human Resource Human Resource Human Resource 1 1
Above code will create physical cache in location “c:tempcache“.
Next time you run the example code again, you will get following output:
Hibernate: insert into DEPARTMENT (NAME) values (?) Human Resource Human Resource Human Resource 0 2
Reason is simple that department entity is stored in physical second level cache and fetched from there. So hibernate will not go to database again.
To download the sourcecode of this project, follow given link.
Sourcecode download
Happy Learning !!
subbareddy
fine..but its a temporary file in local system
Lokesh Gupta
No. They are persistent. When you restart your application, you need not to create them again. You can directly start searching in cache.
Look at second run output in “Physical cache example” section, even we re-run the application and a new hibernate session factory was created, no database hit was there, and you got the department entity from physical cache itself.
subbareddy
thnks
subbareddy
is it useful in real time applications?
and when we used?
Lokesh Gupta
In “real time” applications, when you need to show archive/old data which is in N GB in size, physical cache MUST be used. You can not put load in database for such a huge data, also when thousands users are logged in application all the time.
For example, in a document management system, after a couple of years you will have millions of document records in database. When any user want to view his documents, you can not afford to hit the database as it will virtually kill the database.
Solution is physical cache implementations. They don’t hit database and are really super fast.