Java – Hibernate/Ehcache: evicting collections from 2nd level cache not synchronized with other DB reads

collectionsehcachehibernatejavatransactions

I have an application using JPA, Hibernate and ehcache, as well as Spring's declarative
transactions. The load on DB is rather high so everything is cached to speed things up,
including collections. Now it is not a secret that collections are cached separately
from the entities that own them so if I delete an entity that is an element of such
cached collection, persist an entity that should be an element of one, or update an
entity such that it travels from one collection to another, I gotta perform the eviction
by hand.

So I use a hibernate event listener which keeps track of entities being inserted, deleted
or updated and saves that info for a transaction synchronization registered with Spring's
transaction manager to act upon. The synchronization then performs the eviction once the
transaction is committed.

Now the problem is that quite often, some other concurrent transaction manages to find
a collection in the cache that has just been evicted (these events are usually tenths of a
second apart according to log) and, naturally, causes an EntityNotFoundException to occur.

How do I synchronize this stuff correctly?

I tried doing the eviction in each of the 4 methods of TransactionSynchronization (which
are invoked at different points in time relative to transaction completion), it didn't help.

Best Answer

Essentially what you need to do is to force a read from the database in the event that a collection is in the process of or has just been evicted. One way to do this would be to mark the collection as dirty as soon as a request to evict it has been received but before entering the transaction to change it. Any concurrent transaction which comes along will check the dirty flag and if its set to true, it should get the data from the database otherwise it can read from the cache. You might need to change your DB transaction settings so that concurrent transactions block till the one updating the data finishes so that correct data is read from the DB. Once the transaction finishes, you can then reset the dirty flag to false.

You can also create a lock on the cached collection when an update, insert or delete is due for as long as the eviction lasts. This will ensure that no other transaction can read/change the cached collection till the eviction process finishes.

Related Topic