本文翻译自:How to solve the “failed to lazily initialize a collection of role” Hibernate exception
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 org.hibernate.LazyInitializationException:无法延迟初始化角色集合:mvc3.model.Topic.comments,没有会话或会话被关闭
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: jsp页看起来如下所示:
<%@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. 查看jsp时会引发异常。 In the line with c:forEach loop 与c:forEach循环一致
#1楼
参考:https://stackoom.com/question/nHnf/如何解决-无法延迟初始化角色集合-的Hibernate异常
#2楼
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: 如果您知道每次检索Topic
都想查看所有Comment
则将comments
的字段映射更改为:
@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. 默认情况下,集合是延迟加载的,如果您想了解更多信息,请查看此内容。
#3楼
your list is lazy loading, so the list wasn't loaded. 您的列表是延迟加载的,因此列表尚未加载。 call to get on the list is not enough. 仅凭电话进入名单是不够的。 use in Hibernate.initialize in order to init the list. 在Hibernate.initialize中使用以初始化列表。 If dosnt work run on the list element and call Hibernate.initialize for each . 如果dosnt工作在list元素上运行,并为每个调用Hibernate.initialize。 this need to be before you return from the transaction scope. 这需要在您从事务范围返回之前。 look at this post. 看这个帖子。
search for - 搜索 -
Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session
#4楼
In order to lazy load a collection there must be an active session. 为了延迟加载集合,必须有一个活动会话。 In a web app there are two ways to do this. 在Web应用程序中,有两种方法可以执行此操作。 You can use the Open Session In View pattern, where you use an interceptor to open the session at the beginning of the request and close it at the end. 您可以使用“ 在视图中打开会话”模式,在该模式中,您可以使用拦截器在请求开始时打开会话,并在请求结束时将其关闭。 The risk there is that you have to have solid exception handling or you could bind up all your sessions and your app could hang. 这样做的风险是您必须进行可靠的异常处理,否则您可能会束缚所有会话,并且应用程序可能会挂起。
The other way to handle this is to collect all the data you need in your controller, close your session, and then stuff the data into your model. 处理此问题的另一种方法是收集控制器中所需的所有数据,关闭会话,然后将数据填充到模型中。 I personally prefer this approach, as it seems a little closer to the spirit of the MVC pattern. 我个人更喜欢这种方法,因为它似乎更接近MVC模式的精神。 Also if you get an error from the database this way you can handle it a lot better than if it happens in your view renderer. 同样,如果您通过这种方式从数据库中获取错误,则与在视图渲染器中发生的错误相比,可以更好地处理该错误。 Your friend in this scenario is Hibernate.initialize (myTopic.getComments()). 在这种情况下,您的朋友是Hibernate.initialize (myTopic.getComments())。 You will also have to reattach the object to the session, since you're creating a new transaction with every request. 您还必须将对象重新连接到会话,因为您将为每个请求创建一个新事务。 Use session.lock(myTopic,LockMode.NONE) for that. 为此使用session.lock(myTopic,LockMode.NONE)。
#5楼
From my experience, I have the following methods to solved the famous LazyInitializationException: 根据我的经验,我有以下方法来解决著名的LazyInitializationException:
(1) Use Hibernate.initialize (1)使用Hibernate.initialize
Hibernate.initialize(topics.getComments());
(2) Use JOIN FETCH (2)使用JOIN FETCH
You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. 您可以在JPQL中使用JOIN FETCH语法来显式提取子集合。 This is some how like EAGER fetching. 这有点像EAGER提取。
(3) Use OpenSessionInViewFilter (3)使用OpenSessionInViewFilter
LazyInitializationException often occur in view layer. LazyInitializationException通常在视图层中发生。 If you use Spring framework, you can use OpenSessionInViewFilter. 如果使用Spring框架,则可以使用OpenSessionInViewFilter。 However, I do not suggest you to do so. 但是,我不建议您这样做。 It may leads to performance issue if not use correctly. 如果使用不正确,可能会导致性能问题。
#6楼
it was the problem i recently faced which i solved with using 这是我最近遇到的问题,我通过使用解决了
<f:attribute name="collectionType" value="java.util.ArrayList" />
more detailed decription here and this saved my day. 这里更详细的说明,这节省了我的时间。