Saturday, 7 June 2014

Dealing with org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Hibernate Java

If you are working in Hibernate framework, then you know that one of the key feature of Hibernate is "lazy initialization", which allows framework to lazily initialize dependencies, relationship or association lazily from database on need basis. For example, if you are dealing with User object, which has relationship with Permission object like one user can have multiple permissions, then Hibernate may choose not to initialize the collection which holds all permissions at the time it initialized User object and instead returns a proxy object. At this point, if you close your session and letter tries to access an attribute from Permission object, you will get "org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Hibernate". Why this error comes, because hibernate needs to go database to initialize the proxy object, and connection is already closed. If you remember, what we discussed in difference between get vs load in hibernate that Proxy object is only initialized in Hibernate if you access any attribute other than id itself, that's why you would only see LazyInitializationException if you try to access an attribute other than id. In this article, we will see different scenarios on which you could possibly get "org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Hibernate" and how to solve them appropriately. I have tried to explain reasons which caused the error, and explained the solution as why it will work, but if you still face issues, then feel free to post it here. By the way, good understanding of lazy initialization is also a good Hibernate interview question, so this not only help you to solve this error but also to do well during interviews.


1) Code tries to access a lazy initialized property or collection and session is not available.

This is by far most common reason of "LazyInitializationException: could not initialize proxy". In order to find the reason you need to look your code carefully. Here is one example to understand, how lazy initialization exception comes in Hibernate :

Session s = sessions.openSession();
Transaction tx = s.beginTransaction();

Employee e = (Employee) s.createQuery("from Employee e where e.name=:empName").setString("empName", eName).uniqueResult();
List roles = u.getRoles();

tx.commit();
s.close();

String role = roles.get(0); //  This line will throw error

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
   at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
   at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
   at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)

Easy Solution
Use lazy=false in hibernate mapping file.

Advantage and Disadvantages of lazy=false in Hibernate
org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Hibernate JavaWell, one clear advantage is that it's easy to apply, all you only need to change in Hibernate configuration files e.g. Employee.hbm.xml. It also guarantees that object will be fully initialized. On the other hand, main disadvantage of this approach can be slow performance. Since dependent objects are loaded at the time of persistent object loading, it will increase loading time. Also since now object is fully initialized, there memory consumption would be very high. This can become more severe if your Collection classes are big list of other objects, which are not always accessed.

Better Solution :
The real problem is that you are trying to access a collection in an object that is detached or associated session is closed. You need to re-attach the object before accessing the collection to the current session. You can either reattach the object by calling session.update(object); Or you can move the code which access proxy object to the line before you close the session.

In short, though making lazy=false is simple and sure short way to solve "Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session" it is not a good solution because you are throwing away the Lazy Initialization feature of hibernate. When lazy=false, the collection is loaded in memory at the same time that the object is requested. This means that if we have a collection with 1000 items, they all will be loaded in memory, despite we are going to access them or not. This can result in more memory consumption and slow initialization of object with lot of association or dependency.


2) Upgrading from Hibernate 2.1 to Hibernate 3.0

Cause : Hibernate 3.0 provide lazy loading default as true i.e. lazy ="true"
Solution : In hibernate mapping file set lazy= "false"

Context : You may see "org.hibernate.LazyInitializationException: could not initialize proxy - no Session" while upgrading from hibernate 2.1 to hibernate 3.0. You will suddenly find yourself puzzling what happened, it was working before update. Reasons is, Hibernate 3 introduced lazy loading as the default i.e. lazy="true". If you want it to work the same as before you can mark everything as lazy="false". Alternatively you'll have to start eagerly initialising your entities and associations.


3) Hibernate with JPA Annotation

If you are using hibernate with JPA annotations and manually managing your transactions, then you can also try this as well to deal with LazyInitializationException in Hibernate . In your service class there should be a setter for entity manager with @PersistenceContext. change this to @PersistenceContext(type = PersistenceContextType.EXTENDED). Then you can access lazy property in any where. By the way, its worth remember that, Spring EXTENDED persistence context type is for long conversation pattern, not the session-per-request pattern.

4) Application wide Solution

There are situation, when we want an easy solution and doesn't care anything about performance e.g. for testing or prototyping purpose. In that case you can make following configuration change into your application to avoid this error, but remember the impact eager initialization can cause if this code makes its way to production.

if you are using XML configuration: add default-lazy="false" to your element
if you are using annotation configuration: add @Proxy(lazy=false) to all your entity classes.

That's all about how to fix Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session. We have seen that this error mainly comes when you have closed the connection and trying to access the proxy object which is no fully initialized. Since Proxy object needs a connection, you can either reattach object to the session or carefully avoid writing such code, which access uninitialized Proxy object. Another way to avoid LazyInitializationException is to disable lazy initialization feature of hibernate for your entity classes by using lazy="false" or disable it completely for your application by using default-lazy="false". This solution is not recommended for production use due to performance reason but can be used during prototyping, testing and demo. Don't surprise if you first time see this error, when upgrading from Hibernate 2.1 to 3.0, because that's the version when Hibernate made lazy initialization enabled by default. If you have face this error in any other scenario or trying to solve "org.hibernate.LazyInitializationException: could not initialize proxy - no Session", you can also post your error and code here and we can take a look together.

No comments:

Post a Comment