Friday, January 27, 2012

A Hibernate Proxy and 2 Open Sessions

If you use spring's implementation of OpenSessionInView pattern to support lazy loading in the view layer and you've set singleSession=false you'll most probably hit the infamous:

org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
So what does this mean? It complains about a proxy being associated with two open sessions? How can this happen? Well, this happens when you try to update an entity which directly or indirectly contains lazy-loading proxies that are associated to another session. For example:

The user is loaded from database using session #1. Along with the user, an object graph consisting of all eager-loading fields reachable from user are also loaded. If any of these objects contain lazy-loading fields or collections they will be associated to session #1. The method userDao.update(user) is trying to update the user but is using a new session #2. From hibernate's point of view the user entity is a detached one, so it will try to reattach it to the current session which is #2. But there's a problem because the lazy-loading fields and collections are already associated with session #1, hence we get the exception

One possible solution would be to close session #1 before doing the update. We can do this by calling processDeferredClose/initDeferredClose. This will definitely work for us but it defeats the purpose of using OpenSessionInView with multiple sessions.

Another solution would be to detach the entity from the session as it would be if the session #1 was closed. But how do we do this? We iterate over the graph of entities rooted at entity and evict all lazy-loading proxies or collections from their associated sessions:

I'm not fully confident that this code covers all the angles but you get the idea. Let me know if you have any thoughts on this.