How to fix the “LazyInitializationException” i'

2019-08-07 03:11发布

问题:

Hope you'll be able to help me stop hitting my head against a wall.

Here's my problem, after plenty days of research on many forums, I didn't found any compatible answer with the problem i'm encountering.

I have the org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.supinfo.suppicture.entity.User.pictures, no session or session was closed that seems to be a known Exception, but still drives me crazy...

I've tried to force Eager loading instead of lazy loading but still having the same issue.

Here is my classes :

category.java

@Entity
@Table(name = "category")
@XmlRootElement
public class Category{

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String Name;

@OneToMany(mappedBy = "category")
private Collection<Picture> pictures;

(getters and setters)

user.java

@Entity
@Table(name = "user")
@XmlRootElement
public class User {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String username;

private String password;

private String firstName;

private String lastName;

private String phoneNumber;

private String postalAddress;

private String email;

@OneToMany(mappedBy = "author")
private Collection<Picture> pictures;

    (getters and setters)

picture.java

@Entity
@Table(name = "picture")
@XmlRootElement
public class Picture {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String name;

private String description;

@Column(columnDefinition="longblob")
private byte[] image;

private Date dateOfPublish;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "category_id")
private Category category;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User author;

    (getters and setters)

And here is an example of how I try to retrieve my pictures in database (wich is the only one that have foreign keys)

@Override
public List<Picture> getAllPictures() {
    EntityManager em = emf.createEntityManager();
    try {
        CriteriaQuery<Picture> criteriaQuery = em.getCriteriaBuilder()
            .createQuery(Picture.class);
        criteriaQuery.from(Picture.class);
        return em.createQuery(criteriaQuery).getResultList();
    } finally {
        em.close();
    }
}

Finally called like this :

@Path("/picture")
public class PictureController {

@GET
@Path("/all") @Produces(MediaType.APPLICATION_JSON)
public List<Picture> getAllPictures(){
    return DaoFactory.getPictureDao().getAllPictures();
}

Full stacktrace of exception bellow :

févr. 03, 2019 4:38:48 PM org.hibernate.LazyInitializationException GRAVE: failed to lazily initialize a collection of role: com.supinfo.suppicture.entity.User.pictures, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.supinfo.suppicture.entity.User.pictures, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368) at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111) at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:272) at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.iterator(Lister.java:266) at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.iterator(Lister.java:253) at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:118) at com.sun.xml.internal.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:144) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:345) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681) at com.sun.xml.internal.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:143) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:345) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:578) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:326) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479) at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308) at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:163) at com.sun.jersey.json.impl.provider.entity.JSONListElementProvider.writeList(JSONListElementProvider.java:145) at com.sun.jersey.core.provider.jaxb.AbstractListElementProvider.writeTo(AbstractListElementProvider.java:264) at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1448) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350) at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)

févr. 03, 2019 4:38:48 PM org.apache.catalina.core.StandardWrapperValve invoke GRAVE: "Servlet.service()" pour la servlet jersey-servlet a généré une exception org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.supinfo.suppicture.entity.User.pictures, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368) at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111) at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:272) at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.iterator(Lister.java:266) at com.sun.xml.internal.bind.v2.runtime.reflect.Lister$CollectionLister.iterator(Lister.java:253) at com.sun.xml.internal.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:118) at com.sun.xml.internal.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:144) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:345) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681) at com.sun.xml.internal.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:143) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:345) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:578) at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:326) at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479) at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308) at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:163) at com.sun.jersey.json.impl.provider.entity.JSONListElementProvider.writeList(JSONListElementProvider.java:145) at com.sun.jersey.core.provider.jaxb.AbstractListElementProvider.writeTo(AbstractListElementProvider.java:264) at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1448) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360) at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350) at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538) at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1081) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748)

Please tell me if you need more of my code to help me solve the problem. Thank you in advance.`

A lost developer.

回答1:

Let divide this step by step

1) Your jersey web controller is calling your dao method to get list of pictures (No error)

2) Now your dao layer is getting data from database (No error)

3) Value is returned to your web service controller method (No error)

4) But you are using automatic json converter to convert object data to json. Your pictures has data associated with user. When json converter tries to get data of user the value is null because your transaction has already ended which is resulting in exception. Try ignoring category and user fields during json conversion as shown below.

@JsonIgnore
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "category_id")
private Category category;

@JsonIgnore
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User author;

5) You should not use the picture object directly for json conversion as it will result in cyclic redundancy (infinite loop). Try to create another wrapper class of picture to handle this scenario

Picture -> User -> Picture -> User (Cyclic redundancy)

So for fixing this create three wrapper classes

public class PictureWrapper 
{
    private int id;

    private String name;

    private String description;

    private byte[] image;

    private Date dateOfPublish;

    private CategoryWrapper category;

    private UserWrapper author;
}


public class UserWrapper
{
    private int id;

    private String username;

    private String password;

    private String firstName;

    private String lastName;

    private String phoneNumber;

    private String postalAddress;

    private String email;
}

public class CategoryWrapper
{
    private int id;

    private String Name;
}

Then change getAllPictures method to following

public List<PictureWrapper> getAllPictures() 
{
    List<PictureWrapper> resultList = new ArrayList<PictureWrapper>();
    EntityManager em = emf.createEntityManager();
    try 
    {
        CriteriaQuery<Picture> criteriaQuery = em.getCriteriaBuilder().createQuery(Picture.class);
        criteriaQuery.from(Picture.class);
        List<Picture> list =  em.createQuery(criteriaQuery).getResultList();
    if(list != null && list.size() != 0)
    {
        for(Picture picture : list)
        {
            PictureWrapper pictureWrapper = new PictureWrapper();
            //Load data from picture to picture wrapper with user and category
            resultList.add(pictureWrapper);
        }
    }
    } 
    finally 
    {
        em.close();
    }
    return resultList;
}


回答2:

  • It seems there is no session opened, or no transaction. Your are missing the start and the end of the transaction.
  • There are two options, either your manager yourself the transaction either some Transaction Manager does that in some container.
  • Non-managed environment idiom

    EntityManager em = emf.createEntityManager(); EntityTransaction tx = null; try { tx = em.getTransaction(); tx.begin();

    // do some work ... enter code here tx.commit(); } catch (RuntimeException e) { if ( tx != null && tx.isActive() ) tx.rollback(); throw e; // or display error message } finally { em.close(); }

  • more info here: https://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/transactions.html


回答3:

You need to decorate the OneToMany properties user.pictures and category.pictures with the fetch strategy EAGER.

class Category {
    @OneToMany(mappedBy = "category", fetch = FetchType.EAGER)
    Collection<Picture> pictures;
}

class User {
    @OneToMany(mappedBy = "author", fetch = FetchType.EAGER)
    Collection<Picture> pictures;
}

As a side note, you actually don't need to decorate the ManyToOne properties with the EAGER fetch strategy as this is considered the default behavior.



回答4:

Thanks to Santosh Balaji for the trick ;)