Enterprise Java

Four solutions to the LazyInitializationException – Part 2

This article continues from part 1 of the tutorial.

Load collection by Stateful EJB with PersistenceContextType.EXTENDED

This approach can be applied only to applications that works with Full JEE environments: to use a EJB with PersistenceContextType.EXTENDED.

Check the code below how the DAO would look like:

package com.ejb;

import javax.ejb.Stateful;
import javax.persistence.*;

import com.model.Person;

@Stateful
public class SystemDAOStateful {
 @PersistenceContext(unitName = 'LazyPU', type=PersistenceContextType.EXTENDED)
 private EntityManager entityManager;

 public Person findByName(String name) {
  Query query = entityManager.createQuery('select p from Person p where name = :name');
  query.setParameter('name', name);

  Person result = null;
  try {
   result = (Person) query.getSingleResult();
  } catch (NoResultException e) {
   // no result found
  }

  return result;
 }
}
public class DataMB {
 // other methods and attributes

 @EJB
 private SystemDAOStateful daoStateful;

 public Person getPersonByStatefulEJB() {
  return daoStateful.findByName('Mark M.');
 }
}
<h:dataTable var='dog' value='#{dataMB.personByStatefulEJB.lazyDogs}'>
 <h:column>
  <f:facet name='header'>
   Dog name
  </f:facet>
  #{dog.name}
 </h:column>
</h:dataTable>

Pros and Cons of this approach:

Pros

Cons

The container will control the database transaction

Works only for JEE

The model classes will not need to be edited

N+1 effect may happen

A great amount of Stateful EJBs may affect the container memory.

This approach may create the N+1 effect and the Stateful EJB has a characteristic of not being removed/destroyed while the its session is not expired or until it lost its reference.

Warning: It is not a good practice to hold a reference to an injected EJB in objects that remain in a Pool. The JSF will create a ManagedBean pool to handle better the user requests; when it is necessary the container will increase or decrease the number of ManagedBeans in the pool. In the code of this post imagine if the container create 100 instances of ManagedBeans in the pool, the server will hold 100 Stateful EJBs in memory. The solution to this problem would be a JNDI LookUp to the Stateful EJB.

Load collection by Join Query

This solution is easy to understand and to apply.

See the code below:

 public Person findByNameWithJoinFech(String name) {
  Query query = entityManager.createQuery('select p from Person p join fetch p.lazyDogs where p.name = :name');
  query.setParameter('name', name);

  Person result = null;
  try {
   result = (Person) query.getSingleResult();
  } catch (NoResultException e) {
   // no result found
  }

  return result;
 }
 public Person getPersonByQuery() {
  return systemDAO.findByNameWithJoinFech('Mark M.');
 }
 <h:dataTable var='dog' value='#{dataMB.personByQuery.lazyDogs}'>
  <h:column>
   <f:facet name='header'>
    Dog name
   </f:facet>
   #{dog.name}
  </h:column>
 </h:dataTable>

Pros and Cons of this approach:

Pros

Cons

Just one query will be fired in the database

It would be necessary one query for each accessed collection/lazy attribute

The model classes will not need to be edited

Will bring only the desired data

The N+1 effect will not happen

This approach has the disadvantage of the need of a new query to access each model class collection/lazy attribute. If we need to query only the Person dogs we would need of a specific query. Imagine that we would need to query for the Person emails, it would be necessary a different query.

This approach can be applied to JSE and JEE.

EclipseLink and lazy collection initialization

The relationships default values are:

Relationship

Fetch

@OneToOne

EAGER

@OneToMany

LAZY

@ManyToOne

EAGER

@ManyToMany

LAZY

But the JPA Spec* says that:

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. In particular, lazy fetching might only be available for Basic mappings for which property-based access is used.

As you can see in the text above, the JPA implementation may ignore the hint strategy if it wants to. The EclipseLink has a behavior with JEE and other behavior to JSE. You can see each behavior here: http://wiki.eclipse.org/Using_EclipseLink_JPA_Extensions_%28ELUG%29#What_You_May_Need_to_Know_About_EclipseLink_JPA_Lazy_Loading

We can find in the internet some people saying that even with a lazy collection the EclipseLink does the n+1 queries when the entity is loaded. And we can find this behavior of users with Glassfish and EJB.

Below you will see some tips to use correctly lazy load with EclipseLink:

* JSR-000220 Enterprise JavaBeans 3.0 Final Release (persistence) 9.1.18 and will repeat to the otters JPA relationships.

The end!

In my opinion the best solution is the Join Fetch Query. It is up to you to choose the best solution to your application.

Click here to download the source code of this post. If you want to run the code of this post you will need to create a database named LazyExceptionDB and the JBoss module. Attached to the source code is the Postgres module. If you want to see how to set up the datasource and the Postgres or MySQL module you can see it here: Full WebApplication JSF EJB JPA JAAS.

I hope this post might help you.

If you have any comment or doubt just post it.

See you soon.

Reference: Four solutions to the LazyInitializationException from our JCG partner Hebert Coelho at the uaiHebert blog.

Hebert Coelho

Senior Java Development, with 4 certifications and a published book about JSF (portuguese only). Founder of the blog uaiHebert.com visited from more than 170 different countries.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Me
Me
12 years ago

Clap clap for you mate. Nice and easy.

Leonardo Costa Borges
11 years ago

Nice tips… Congratulations!

PabloC
PabloC
10 years ago

Excellent and very useful note!, Thanks!!!!

Rob Mitchell
Rob Mitchell
9 years ago

Just a few quick notes on how to design entities and/or your code to handle the infamous LIE. One other way to handle LIE is to essentially wrap those areas of your code (based on testing) to catch LIE and return something else that say “this collection you’re trying to access may have data, but I don’t have it right now.” You can design a lazy loading pattern to queue this request as a Promise and pickup the results at a later time. Yes, the “join fetch” and “left join fetch” are your best options but you’ll have to be… Read more »

RLAguna
RLAguna
9 years ago

Your article is really good, it helped a lot! I follow your fourth approach (load collection by fetch query) but it throws: “..SQLGrammar exception “You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘fetch e.almacenesFree where e.mail = ‘test’ ” public Estandar buscarPorMailConAlmacenesGratis(String mail) { Estandar ret = null; Query query = em .createNativeQuery(“select e from estandar e left join fetch e.almacenesFree where e.mail = :email”); query.setParameter(“email”, mail); try { ret = (Estandar) query.getSingleResult(); } catch (NoResultException e) { } return ret; } And… Read more »

Rob Mitchell
Rob Mitchell
9 years ago
Reply to  RLAguna

When you use “createNativeQuery” then you must use regular SQL, not JPQL. So replace the actual query with this:

Estandar ret = null;
try {
String sql = “select * from estandar e left join almacenesFree af on e.almacenesFree_id = af.id and e.mail=”+mail;

ret = (Estandar) em.createNativeQuery(sql, Estandar.class)
.setParameter(“email”, mail)
.query.getSingleResult();

} catch (…) {
} finally {
}

i haven’t tried the code above, so beware.

Thx
-Rob

luis
luis
8 years ago

excellent explanation mate, this make me analize clearly my application and decide which solution to use. I think i’m going with fetchtype EAGER, cause my database only consist in catalog tables and application behavior (i.e. menus and metadata properties). So in this case I don’t think my application would have a 400,000,000 menu options for example.

Back to top button