LazyInitializationException with hibernate and spr

2019-08-07 01:36发布

问题:

I need help to find a way to fix this error:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.example.myproject.domains.Person.tasks, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155)
at org.hibernate.collection.internal.PersistentSet.isEmpty(PersistentSet.java:166)
at com.lyncode.jtwig.content.model.compilable.For$Compiled.handleCollection(For.java:132)
at com.lyncode.jtwig.content.model.compilable.For$Compiled.render(For.java:98)
at com.lyncode.jtwig.content.model.compilable.Sequence$Compiled.render(Sequence.java:80)
at com.lyncode.jtwig.content.model.renderable.Replacement.render(Replacement.java:32)
at com.lyncode.jtwig.content.model.compilable.Sequence$Compiled.render(Sequence.java:80)
at com.lyncode.jtwig.parser.JtwigParser$CompiledDocument.render(JtwigParser.java:67)
at com.lyncode.jtwig.parser.JtwigParser$CompiledDocument.render(JtwigParser.java:67)
at com.lyncode.jtwig.mvc.JtwigView.renderMergedTemplateModel(JtwigView.java:102)
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
...

the server throws this exception while i trying to enter to: http://localhost:8080/myproject/persons/1

the controller is:

@RequestMapping("/persons/{id}")
public ModelAndView updateMemeber(@PathVariable Integer id) {

    ModelAndView mav = new ModelAndView("user/show");

    mav.addObject("title", "Show User");
    mav.addObject("person", personService.get(id));
    return mav;

}

and the models are defined like this:

Person model:

@Entity
@Table(name="persons")
public class Person {

    /**
     * The rest of attributes.
     *
     */

    @OneToMany(fetch = FetchType.LAZY, mappedBy="person")
    public Set<Task> tasks;

    /**
     * get a set of tasks
     */
    public Set<Task> getTasks() {
        return this.tasks;
    }


}

Task model:

@Entity
@Table(name="tasks")
public class Task {

    /**
       * get a set of tasks
       */

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="person_id")
    private Person person;



}

I read many about this issue but any solution worked for me; if you need something more just let me know.

回答1:

You're getting this error because collections, in this case Set<Task>, are lazy-loaded by default in Hibernate.

What is "lazy-loading"? It means that the main object is loaded from the database, but the collection is only loaded once it's needed by something calling getTasks(), in this case. However, the Hibernate session still has to be open for it to work, because it's another call to the database.

What's happening in your case is this: you're asking Hibernate for the object, and it queries it but does so without the Set<Task> collection. Then the Hibernate session closes. Your UI, whether it's a JSP or JSF or servlet or whatever, then tries to get at the Person's "tasks" property, probably through an expression, which in turn invokes getTasks(). So Hibernate tries to make a second call to the database to get the Set<Task> collection, but the session has already closed. Hence the exception.

There are two possible fixes for this:

  • Add a filter that keeps the session open until the UI is done rendering. Have a look at OpenSessionInViewFilter, which comes with Spring.
  • Change the FetchType to "EAGER" for the tasks collection.

The first fix will handle similar situations through your application regardless of the entity. The second fix is specific to this usage of the Person entity, so might be less useful.



回答2:

I am not too familiar with Spring MVC, but I know in JSF you would need to properly construct Person.class using an @PostConstruct annotation - otherwise Person and Task will not be properly initialized.