Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

How to Use Hibernate Query Cache

In this article we will see how to make the best use of Hibernate Query Cache, a type of standard cache used by the ORM framework

In the first part of this tutorial, you saw how First Level Cache works in Hibernate world. From now on, we'll take a look at the other two types: Query Cache and Second Level Cache (L2).

Query Cache

Now we will see an "extension" of L1 Cache, Query Cache. Note that all objects of L1 were loaded using the "load()" method, available in the Session object, because it makes a query to the L1 cache before going to the database.

But the "load()" is only useful when we have the key/id of the object in question, otherwise we would have to run a query by executing "session.createQuery()" and you get a big surprise: The L1 cache does not work for this case.

When executing "createQuery()", it goes straight in the database without caring for the L1 cache, bringing a big problem: The L1 cache becomes useless. To work around this problem is that the Query Cache emerged.

The Query Cache stores inL1 Cachethe ID's of the returned results, that is, as if you had running various "load()" on various objects. Let's see an example in Listing 1.

Listing 1. Using Query Cache

Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Person p where p.id=1");
query.setCacheable(true);
Iterator it = query.list().iterator();
while (it.hasNext()) {
	Person p = (Person) it.next();
	System.out.println(p.getFirstName());
}
query = session.createQuery("from Person p where p.id=1");
query.setCacheable(true);
it = query.list().iterator();
while (it.hasNext()) {
	Person p = (Person) it.next();
	System.out.println(p.getFirstName());
}
tx.commit();
session.close();

The point of attention above is the line "query.setCacheable(true)" which says that the result of this query should be cached.

As well as to set the query as "cacheable", you need to change a setting of your Hibernate configuration file, as shown in Listing 2.

Listing 2. Enabling Query Cache

<property name="hibernate.cache.use_query_cache">true</property>

With these two points your application is ready to use Query Cache and evict too many searches in the database.

L2 cache or Second-Level Cache

Unlike the L1 cache, the L2 cache is available for all objectsSessionscreated by the SessionFactory. Imagine, for example, you have a table in the database with the application settings to be maintained throughout the cycle of the same and will never be changed. You can use the L2 cache to keep these settings available to all other Sessions, preventing you to need to consult the database every time you need a setting.

The L2 cache is attached to the SessionFactory object and its entire life cycle, ie, it is "born" and "die" in this very moment.

Figure 1. Cache L2

In Figure 1 we realized it was added one more layer of communication between the L1 cache and the database, this means that the L1 cache communicates with the L2 cache and this communicates with the database.

Then follow the flow would be: The Session searches for the L1 cache which, in turn, searches the L2 cache which in turn returns the data or go to the database to make a search. When a query is made directly to the database, both the L1 cache and the L2 cache are updated.

When an object does not exist in L1 cache but there is in the L2 cache, this is replicated to the L1 cache, avoiding a query to the L2 cache. So give some thought what would happen if an object exists in the L1 cache and L2 cache and you took a "session.evict(object)."

The answer is: The L1 cache would be clean, but not L2 cache. Then the same would be replicated again from the L2 cache to the L1, avoiding the query to the database. In this case we would have to call the "evict" of the SessionFactory. Let's see how in Listing 3.

Listing 3. Cleaning of L2 Cache object

public void evict2ndLevelCache() {
  try {
	  Map<String, ClassMetadata> classesMetadata = sessionFactory.getAllClassMetadata();
	  for (String entityName : classesMetadata.keySet()) {
		  logger.info("Evicting Entity from 2nd level cache: " + entityName);
		  sessionFactory.evictEntity(entityName);
	  }
  } catch (Exception e) {
	  logger.logp(Level.SEVERE, "SessionController", "evict2ndLevelCache", "Error evicting 2nd level hibernate cache entities: ", e);
  }
}

We clean the object of L2 cache, but remember that it still exists in the L1 cache, the L2 cache is never accessed. So if you want to force the query to the database, you must clear the L1 cache and L2 cache.

As mentioned earlier, the L2 cache is in scope of the SessionFactory, which makes it be accessed by all Sessions created by the SessionFactory (usually an application has only one SessionFactory). So let's look at an example in Listing 4of two Sessions accessing the same object that is in the L2 cache.

Listing 4. Two Sessions accessing an object in L2 Cache

// Object is searched for the first time and loaded in Cache L1 and Cache L2
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());


// We search the object again, it is return by the Cache L1 because it is in the same Session
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());


// We clean the object from the Cache L1
session.evict(department);
		  
// We search the object again, it is copied from Cache L2 to Cache L1
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());


// We search the object again, but now in a new Session. It is copied from Cache L2 to Cache L1
department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());


System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount());           //Prints 1
System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());   //Prints 2


Output: 1 2

Note that at any time we clean the L2 cache, so in this case the object is always returning the L2 cache without consulting the database.

The L2 cache most frequently used by Hibernate is EhCache, which makes the role described above. To set it up simply add the code in Listing 5 in your Hibernate configuration file.

Listing 5. Enabling EhCache

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>

It's done, now EhCache is enabled. Now we only need to create a config file to set all its parameters, the ehcache.xml. See Listing 6.

Listing 6. ehcache.xml

  <ehcache>    
  <cache       name="com.somecompany.someproject.domain.Country"       maxElementsInMemory="10000"       eternal="false"       timeToIdleSeconds="300"       timeToLiveSeconds="600"       overflowToDisk="true"   />   </ehcache>

Conclusion

With this, we finish this serie of tutorials regarding Hibernate Cache. We're now ready to go on and understand the best ways to use this feature into your projects, as well as knowing that it doesn't matter if you use or not, it'll be alwyas in there. Good studies!



Julio is a System analyst and enthusiast of Information Technology. He is currently a developer at iFactory Solutions company, working in the development of strategic systems, is also a JAVA instructor. He has knowledge and experi...

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login