views:

976

answers:

3

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.

+1  A: 

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.

Lonzo
It is evicted outside of a transaction, by the way. And I gotta look for the API to mark them dirty, thanks. Also, how do I make Hibernate synchronize on that lock you've suggested to add?
Kirill
Apparently, PersistentCollection's dirty flag won't do, becausedifferent transactions get different instances of the samecollection.As for locks, I'm gonna look into that next, and would really appreciate it if somebody pointed me to the proper API.EhCache doesn't support locking as far as I know, looked at thatfirst thing.
Kirill
A: 

Why can't you must keep the collections up to date? i.e. when you add an object, add the object to the collection it belongs to. When you delete an object, remove it from the collection it is in. In my experience when using a cache with hibernate or jpa the state of the object (not the state of the database) is cached so you need to make sure your object model in memory is in sync with the object model on the database.

Or am I missing something? Why can't you simply keep the collections uptodate?

Michael Wiles
It's a multithreaded application, passing the same up-to-date instance with an up-to-date collection around seems kind of difficult as there're all kinds of concurrent operations that take different time to complete and I tend to use EntityManager.getById alot to fetch the latest state of an entity.
Kirill
A: 

i think you must refer this link : - http://stackoverflow.com/questions/1470502/hibernate-clean-collections-2nd-level-cache-while-cascade-delete-items see, hibernate does not actually delete the object from the cache.. rest u can get the answer from above link

Mrityunjay