Thursday 17 March 2016

How Hibernate cache works


After working on performance of web applications , I realized its time to share my learning of hibernate with all of you.
There are three terminologies used with hibernate cache :

  • Hibernate first level cache
  • Hibernate second level cache
  • Hibernate query cache

Hibernate first level cache


Hibernate first level cache is by default active.So if you load a hibernate entity via named query , get() or load() method in a session , then that entity is stored in hibernate first level cache. If you again fetch this entity in the same session then no Select sql query is fired.

example :

       
// new session started
session.getNamedQuery("from EntityName").list();    //load all entities via named query and storing in cache
session.load(EntityName.class, 1L);    // No sql query fired
session.get(EntityName.class, 1L);    // No sql query fired
//session ended



Hibernate Second Level Cache


Hibernate first level cache is at session level, whereas hibernate second level cache is at SessionFactory level. Any data that is allowed to store at this cache level is maintained at SessionFactory level. SessionFactory object is created per JVM means one JVM application connected to a datasource has only one sessionFactory object.


Lets take an example of an entity to understand how second level cache stores data .

       
@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class MyCacheEntity {

    @Id
    @GeneratedValue
    private long id;
 
    private String name;

    private int age;

    //getters and setters
}



Second  level cache in hibernate are provided by some third party second level cache providers like ehcache.
These providers require only configuration details like entity cache regions,max memory or max time to hold cached data.

To enable second level cache we have add @org.hibernate.annotations.Cache annotation at entity level.

By this will start storing data in its second level cache as a map of key-value.
Key as ids and value as raw data.


Second level cache MAP

       
*---------------------------*
| MyCacheEntity Data Cache  |
|---------------------------|
| 1  -> [ "rakesh", 20 ]    |
| 2  -> [ "rahul", 30 ]     |
| 3  -> [ "rakesh", 32 ]    |
| 4  -> [ "sachin", 25 ]    |
*---------------------------*


This cache data has advantage only when you use it via hibernate query like NamedQuery.

So lets create a named query to fetch data from MyCacheEntity.
       
public String getEntityByName(String name) {
   String hql = "SELECT ce FROM MyCacheEntity ce where ce.name=:name";
   Query queryEntityByName = (Query) session.getNamedQuery(hql);
   queryEntityByName.setParameter("name", name);
   queryEntityByName.setCacheable(true);
   return queryEntityByName.list().get(0);
}


Query Cache


Here we start with Query cache.You can enable query cache by setting setCacheable(true).
By setting this hibernate stores a cache having data as map in which key contains the sql query fired with data passed
and value contains list of ids as result from that query as shown below.


Query cache MAP

       
*-------------------------------------------------------------------------------*
|                                 Query Cache                                   |
|-------------------------------------------------------------------------------|
|["SELECT ce FROM MyCacheEntity ce where ce.name=?" , ["rakesh"] ]  ->  [1,3 ]  |
*-------------------------------------------------------------------------------*


So if you have query cache enabled, then hibernate will look for ids 1 and 3.

It will have 3 stages :


  • First it will check these ids in hibernate 1st  level cache , i.e. in current hibernate session.
  • If some ids not found in 1st level cache, then hibernate checks in 2nd  level cache i.e. Second level cache Map (here MyCacheEntity Data Cache) at SessionFactory level .
  • Still if some ids not found in 2nd level cache, then hibernate will fire sql select query for each id separately. For example if n ids left for 3rd case , then n select queries will be fired.


This third case is important to understand as it impacts on performance of an application.

So it is always important to implement a second level cache with query cache.



Thanks

4 comments:

  1. Nice blog.. Quite helpful..

    ReplyDelete
  2. Hi! I try decide problem RTSP live-streaming video from two sources with overlay (PIP, in Windows). I found in the Internet your blog:
    http://www.oodlestechnologies.com/blogs/PICTURE-IN-PICTURE-effect-using-FFMPEG
    Tried – everything works fine for the output FILE. But the transfer of the output stream on the cache FFserver (http://localhost:8090/feed1.ffm) there is a problem - it seems for some reason does not work overlay from filter_comlex, because receive RTSP stream has video only from the main source. Help me, please, what could be the problem ?
    Best regards,
    Gennadiy Yuritskiy
    ugv@mail.ru

    ReplyDelete
  3. hibernate cache, so useful. Well explained

    ReplyDelete
  4. Now I know hibernate cache internals, thanks

    ReplyDelete