How to solve the LazyInitializationException when using JPA and Hibernate

JavaHibernateJpaOrmLazy Initialization

Java Problem Overview


I am working on a project for a customer who wants to use lazy initialization. They always get "lazy initialization exception" when mapping classes with the default lazy loading mode.

@JoinTable(name = "join_profilo_funzionalita", joinColumns = {@JoinColumn(name =    "profilo_id", referencedColumnName = "profilo_id")}, inverseJoinColumns = {@JoinColumn(name = "funzionalita_id", referencedColumnName = "funzionalita_id")})
//@ManyToMany(fetch=FetchType.EAGER) - no exceptions if uncommented
@ManyToMany 
private Collection<Funzionalita> funzionalitaIdCollection;

Is there a standard pattern using JPA classes to avoid this error?

Snippets are welcome, thanks a lot for your time.

Java Solutions


Solution 1 - Java

Hibernate 4.1.6 finally solves this issue: https://hibernate.atlassian.net/browse/HHH-7457

You need to set the hibernate-property hibernate.enable_lazy_load_no_trans=true

Here's how to do it in Spring:

<bean id="entityManagerFactory"
	  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="myDataSource"/>
	<property name="packagesToScan" value="com.mycompany.somepackage"/>
	<property name="jpaVendorAdapter" ref="hibernateVendorAdapter"/>
	<property name="jpaDialect" ref="jpaDialect"/>
	<property name="jpaProperties">
		<props>
			<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
		</props>
	</property>
</bean>

Voila; Now you don't have to worry about LazyInitializationException while navigating your domain-model outside of a hibernate-session (persistence-context in "JPA-speak")

Solution 2 - Java

There are many ways to pre-fetch properties, so they are there after session is closed:

  1. Call appropriate getter. After field is fetched into bean it is there after session is closed.
  2. You may initialize field in EJBQL query , look for JOIN FETCH keyword.
  3. Enable AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS if you're on a Hibernate version that supports it.

Several problems may occur when you try these solutions:

  1. The getters' invocation may be optimized away by the JIT compiler (sometimes this takes a while).
  2. The entities you are trying to JOIN FETCH may be linked through multiple 'many' relationships involving List's. In this case the resulting query returns ambiguous results and Hibernate will refuse to fetch your data in a single query.
  3. There is already one interesting bug related to AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS. And there will be more because as the hibernate guys say: Note: this may happen outside of the transaction and is not safe. Use with caution. You're on your own mostly.

The best way to go is to try a JOIN FETCH first. If that doesn't work try the getter approach. If that gets messed up at runtime by the JIT compiler, assign the result to a public static volatile Object.

Or stop using Hibernate...

Solution 3 - Java

Note that you shouldn't use hibernate.enable_lazy_load_no_trans pre Hibernate 4.1.7, as it leaks connections. See https://hibernate.onjira.com/browse/HHH-7524

Solution 4 - Java

LazyInitializationException means that you are calling the collection after the hibernate session has closed, or after the object has been detached from the session.

You need to either re-attach the object to hibernate session, change the place where you are calling the collection, or move the boundary of where the session gets closed to a higher layer.

Solution 5 - Java

The best way to solve the LazyInitializationException is to use the JOIN FETCH directive in your entity queries.

FetchType.EAGER loading is bad for performance. Also, there are anti-patterns such as:

Which you should never use since they either require the database connection to be open for the UI rendering (Open Session in View), or a database connection is needed for every lazy association that is fetched outside of the initial Persistence Context (hibernate.enable_lazy_load_no_trans).

Sometimes, you don't even need entities, and a DTO projection is even better. You should fetch entities only when you need to modify them. For read-only transactions, DTO projections are better.

Solution 6 - Java

OpenSessionInView is one pattern to deal with this problem. Some info here:

http://www.hibernate.org/43.html

You'll want to be cautious when implementing this pattern and understand the implications. Each time you navigate a lazy association in the view it will fire off another SQL query to load the data. If your use cases are such that the number and size of these SQL queries is small then this may not matter. Make sure that at a minimum you adjust your logging settings so you can see what kind of queries Hibernate is "magically" executing in the background for you to load the data.

Also consider the kind of application you are writing. If you're not dealing with remoting (no web services, no AJAX-based web client) then OSIV may work very nicely. However, if a remoting serializer starts to walk the entire object graph, it will likely trigger a ridiculous number of SQL queries and cripple your DB and app server.

Solution 7 - Java

When you are using collection and you want to initialize it with lazy loading then use that collection before session close. If session is close after that if you want to use then you get lazyinitializeException because lazy is try by default.

Solution 8 - Java

The Oracle Java tutorials point out that "Enterprise beans support transactions, the mechanisms that manage the concurrent access of shared objects." So, in order to handle the Lazy Fetch issues I create a Stateless Java Session Bean and then get all of the sub classes I need before returning from the method. This avoids the lazy fetch exception. Oracle has also referred to this as a "Session Façade" core J2EE pattern. This pattern seems better than some of the other practices mentioned.

Solution 9 - Java

I'm working on a project that aims to solve common JPA problems when mapping entities to DTOs using ModelMapper. This issue has already been solved on the project. Project link: JPA Model Mapper

> "Its crucial for performance to declare entities as lazy load so we > don't need to fetch all related entities every time we need some data. > But this technique leads to some issues. The most common one is the > LazyInitializationException that can be pretty annoying sometimes. > Most of the time we would just want a null object for a not loaded > entity instead of an object that throws an exception if accessed..."

Source: JPA Model Mapper

Therefore, in the project we deal with LazyInitializationException by setting null for all not loaded entities. The examples below show how it works.

Remapping an entity setting null for all not loaded entities:

TypedQuery<SystemEntity> query =
        em.createQuery("select s from SystemEntity s where s.id = 1",  SystemEntity.class);

SystemEntity system = query.getSingleResult();
return new JpaModelMapper(em).mapEntity(system, SystemEntity.class);

Remapping an entity to a DTO setting null for all not loaded entities:

TypedQuery<SystemEntity> query =
        em.createQuery("select s from SystemEntity s where s.id = 1",  SystemEntity.class);

SystemEntity system = query.getSingleResult();
return new JpaModelMapper(em).mapEntity(system, SystemDTO.class);

For more informations please see JPA Model Mapper

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrupertinView Question on Stackoverflow
Solution 1 - JavaandreakView Answer on Stackoverflow
Solution 2 - Javajb.View Answer on Stackoverflow
Solution 3 - JavaHaniView Answer on Stackoverflow
Solution 4 - JavaDaniel AlexiucView Answer on Stackoverflow
Solution 5 - JavaVlad MihalceaView Answer on Stackoverflow
Solution 6 - Javacliff.meyersView Answer on Stackoverflow
Solution 7 - JavaSANTOSH KumarView Answer on Stackoverflow
Solution 8 - JavaK.NicholasView Answer on Stackoverflow
Solution 9 - JavaVinícius M. FreitasView Answer on Stackoverflow