我有这样一个问题:
org.hibernate.LazyInitializationException:惰性初始化role: mvc3.model.Topic.comments集合失败,没有会话或会话已关闭
下面是模型:
@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;
}
}
调用model的控制器如下所示:
@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);
}
}
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>
在查看jsp时,将引发异常。在c:forEach循环的行中
嗨,大家都很晚才发,希望能帮助到其他人。
提前感谢@GMK的这篇文章
当懒=“真正的”
Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();
现在,如果我在关闭会话后访问'set',它会抛出异常。
我的解决方案:
Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();
现在我可以在关闭Hibernate会话后访问“set”。
在第二次执行生成JWT令牌的方法后,我得到了这个错误。
line user.getUsersRole().stream().forEachOrdered((ur) -> roles.add(ur. getroleid ()));生成错误。
// MyUserDetails.java
@Service
public class MyUserDetails implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String email) {
/* ERROR
/* org.hibernate.LazyInitializationException: failed to
/* lazily initialize a collection of role:
/* com.organizator.backend.model.User.usersRole,
/* could not initialize proxy - no Session */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));
在我的例子中,@Transactional注释解决了它,
// MyUserDetails.java
import org.springframework.transaction.annotation.Transactional;
@Service
public class MyUserDetails implements UserDetailsService {
@Override
@Transactional // <-- added
public UserDetails loadUserByUsername(String email) {
/* No Error */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));
问题的根源:
默认情况下,hibernate惰性加载集合(关系),这意味着无论何时在代码中使用集合(这里是comments字段)
主题课)
hibernate从数据库中获取,现在的问题是,您正在获得控制器中的集合(其中
JPA会话已关闭)。这是导致异常的代码行
(你正在加载注释集合):
Collection<Comment> commentList = topicById.getComments();
您在您的控制器(JPA会话已经结束的地方)中获得“comments”集合(topic.getComments()),这会导致异常。如果你有
JSP文件中的注释集合像这样(而不是在控制器中获取它):
<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>
出于同样的原因,仍然会出现相同的异常。
解决问题:
因为FetchType只能有两个集合。实体类中的Eager(急切获取的集合),因为延迟加载更多
比急切加载更有效,我认为这种解决问题的方法比仅仅将FetchType更改为急切更好:
如果你想初始化懒集合,并让这个工作,
最好将这段代码添加到web.xml中:
<filter>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这段代码所做的是它将增加您的JPA会话的长度,或者正如文档所说,它被用于“允许在web视图中延迟加载,尽管原始事务已经完成。
这样,JPA会话打开的时间会更长一点
您可以在JSP文件和控制器类中惰性加载集合。