Thursday, August 24, 2006

Evict collection from Hibernate second level cache


Hibernate allows persistent objects to be cached in its second level cache(The first level cache in Hibernate is the Session object which is ON by default). Applications can switch on the second level cache. When a object is being retrieved by the application through Hibernate, Hibernate first checks in its Session cache and then the Second level cache to see if the object has be retrieved already. If it finds it either the Session cache or the Second level cache, it will NOT fire a query to the database.
While configuring second level cache, the object can be cached and also the collections contained in the object can be cached. Have a look at the following example:

<hibernate-mapping default-lazy="false" >
<class name="org.myapp.ho.Parent" table="Parent">
<b><cache usage="read-only" /> </b>
<id name="id" type="Integer" column="ID" />
<set name="myChildren">
<b> <cache usage="read-only"/> </b>
<one-to-many class="org.myapp.ho.Child"/>
</set>
</class>
</hibernate-mapping>



<hibernate-mapping default-lazy="false" >
<class name="org.myapp.ho.Child" table="Child">
<b><cache usage="read-only" /></b>
<id name="id" type="Integer" column="ID" />
</class>
</hibernate-mapping>


Note that we have used the cache setting at 3 places:
1) The org.myapp.ho.Parent object
2) The "myChildren" collection in the org.myapp.ho.Parent object
3) The org.myapp.ho.Child object
When you configure a collection to be second level cached in Hibernate, it internally maintains a SEPERATE cache for these collection than the one which it uses to cache the parent objects. So in the example above, the “myChildren” will be cached separately than the org.myapp.ho.Parent object.
There might be cases where applications would want to evict objects from the cache. If its the Session cache from which the application has to evict the object then the call to Session.evict will cascade even to collections and will evict the collection from the *Session cache*. However, if the object(and the collections contained in it) have to be evicted from the second level cache, then the application has to *explicitly* call the evictCollection method on the SessionFactory to remove the *collection* contained in the Parent object. The reason behind this is, as already mentioned, the collections are cached separately, than the parent objects, in the second level cache.
So, in our example above, if we have to evict the Parent with id 500 and its collection from the second level cache, then here’s what has to be done:

SessionFactory sf = MyUtil.getSessionFactory();
//this will evict the Parent Object from the second level cache
sf.evict(org.myapp.ho.Parent.class,new Integer(500));
//this will evict the collection from the second level cache for the Parent with id=500
sf.evictCollection(org.myapp.ho.Parent.class.getName() + ".myChildren", new Integer(500));


The first parameter to the evictCollection method is the ‘roleName’ of the collection. The roleName is formed as follows:

roleName = NameOfTheParentClass + "." + NameOfTheCollectionInsideTheParent

The second parameter the evictCollection method is the id of the parent object, to which this collection belongs.

14 comments:

Sudarshan said...

Hi Jai,

Nice explaination about the evicting the collection. Just off the track, I want to ask something about second level caching itself. I'm using JBoss TreeCache for second level caching. But when I see the SessionFactory.getStatistcs().logSummary() everytime I got missed and hit second level cache count to ZERO. Can you please explain me the reason for it?

Thanks in advance
Sudarshan Varma

Jaikiran said...

"But when I see the SessionFactory.getStatistcs().logSummary() everytime I got missed and hit second level cache count to ZERO. Can you please explain me the reason for it?"

Sudarshan,
You will have to enable the statistics generation property, to be able to get the statistics logs.

Have a look at Section 19.3 at:
Enable Hibernate Statistics.
You will have to set hibernate.generate_statistics=true

Lakshmi said...

Hi jai,
Nice example. Have you tried using Jbosscache with Hibernate and container managed transactions in websphere ?

Jaikiran said...

Lakshmi,

I have used JBossCache with Hibernate in CMT in JBoss but not in Websphere. Any specific reason why you ask this?

Lakshmi said...

yes, I have been looking for some help on hibernate and Jboss forums specifically for deployment on WAS6.0, which appears to have introduced custom JTA apis. If you are interested, you could visit the forum link for more info.

http://forum.hibernate.org/viewtopic.php?t=968608

Jaikiran said...

Saw that link. Sorry, no clue what might be wrong.

Anonymous said...

Did you try AspectWerkZ with Websphere 6.0/6.1. I saw message in mailing list about the problem posted by you. Can you let me know does it solve, If yes how


Akl

Jaikiran said...

Did you try AspectWerkZ with Websphere 6.0/6.1. I saw message in mailing list about the problem posted by you

Unfortunately, i wasnt able to get it working.

Chocka said...

Good explanation. I wasn't sure about the session.evict behavior when the object had a collection inside it. This article cleared by doubt. Thank you.

andsegu said...

thanks dude, i was having problems with collections caching. All that i needed was an example.

Ryan R. LaMothe said...

Awesome blog post, saved me tons of time. Thanks!

siddu said...

Nice Article. Thanks for posting.

Ondrej Medek said...

Hi Jai, nice article. Is there any way, how to clean everything from the second level cache? I always forgot to add something to my cleaning method.

Andreas Berger said...

I supplied an fix for this issue at github unti it is included in a hibernate release you can use a workaround I posted at stackoverflow.