I have this problem:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
Here is the model:
@Entity @Table(name = "T_TOPIC") public class Topic { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; @ManyToOne @JoinColumn(name="USER_ID") private User author; @Enumerated(EnumType.STRING) private Tag topicTag; private String name; private String text; @OneToMany(mappedBy = "topic", cascade = CascadeType.ALL) private Collection<Comment> comments = new LinkedHashSet<Comment>(); ... public Collection<Comment> getComments() { return comments; } }
The controller, which calls model looks like the following:
@Controller @RequestMapping(value = "/topic") public class TopicController { @Autowired private TopicService service; private static final Logger logger = LoggerFactory.getLogger(TopicController.class); @RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET) public ModelAndView details(@PathVariable(value="topicId") int id) { Topic topicById = service.findTopicByID(id); Collection<Comment> commentList = topicById.getComments(); Hashtable modelData = new Hashtable(); modelData.put("topic", topicById); modelData.put("commentList", commentList); return new ModelAndView("/topic/details", modelData); } }
The jsp-page looks li the following:
<%@page import="com.epam.mvc3.helpers.Utils"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ page session="false" %> <html> <head> <title>View Topic</title> </head> <body> <ul> <c:forEach items="${commentList}" var="item"> <jsp:useBean id="item" type="mvc3.model.Comment"/> <li>${item.getText()}</li> </c:forEach> </ul> </body> </html>
Exception is rised, when viewing jsp. In the line with c:forEach loop
The right way to fix a LazyInitializationException is to fetch all required associations within your service layer. The best option for that is to load the entity with all required associations in one query.
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 the connection is already closed.
If you know that you'll want to see all Comment
s every time you retrieve a Topic
then change your field mapping for comments
to:
@OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL) private Collection<Comment> comments = new LinkedHashSet<Comment>();
Collections are lazy-loaded by default, take a look at this if you want to know more.
From my experience, I have the following methods to solved the famous LazyInitializationException:
(1) Use Hibernate.initialize
Hibernate.initialize(topics.getComments());
(2) Use JOIN FETCH
You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. This is some how like EAGER fetching.
(3) Use OpenSessionInViewFilter
LazyInitializationException often occur in view layer. If you use Spring framework, you can use OpenSessionInViewFilter. However, I do not suggest you to do so. It may leads to performance issue if not use correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With