我有这样一个问题:

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循环的行中


当前回答

在我的情况下,下面的代码是一个问题:

entityManager.detach(topicById);
topicById.getComments() // exception thrown

因为它从数据库中分离,当需要时Hibernate不再从字段中检索list。所以我在分离之前初始化它:

Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm

其他回答

在我的Spring-Boot项目中,spring.jpa.open-in-view在application.properties中被设置为false。将其设置为true就解决了这个问题。

导致这个问题的原因是,当到数据库的“连接”关闭时,代码正在访问一个惰性JPA关系(持久上下文是Hibernate/JPA的正确名称)。

在Spring Boot中解决这个问题的一个简单方法是定义一个服务层并使用@Transactional注释。方法中的注释创建一个事务,该事务将传播到存储库层,并在方法完成之前保持打开持久性上下文。如果您访问事务方法中的集合,Hibernate/JPA将从数据库中获取数据。

在您的情况下,您只需要在TopicService中使用@Transactional注释findTopicByID(id)方法,并强制在该方法中获取集合(例如,通过询问其大小):

    @Transactional(readOnly = true)
    public Topic findTopicById(Long id) {
        Topic topic = TopicRepository.findById(id).orElse(null);
        topic.getComments().size();
        return topic;
    }

此问题是由于在关闭hibernate会话的情况下访问属性造成的。控制器中没有hibernate事务。

可能的解决方式:

Do all this logic, in the service layer, (with the @Transactional), not in the controller. There should be the right place to do this, it is part of the logic of the app, not in the controller (in this case, an interface to load the model). All the operations in the service layer should be transactional. i.e.: Move this line to the TopicService.findTopicByID method: Collection commentList = topicById.getComments(); Use 'eager' instead of 'lazy'. Now you are not using 'lazy' .. it is not a real solution, if you want to use lazy, works like a temporary (very temporary) workaround. use @Transactional in the Controller. It should not be used here, you are mixing service layer with presentation, it is not a good design. use OpenSessionInViewFilter, many disadvantages reported, possible instability.

一般来说,最佳解是1。

模型类Topic中的集合注释是惰性加载的,如果你不使用fetch = FetchType注释它,这是默认的行为。热切的特别。

findTopicByID服务很可能正在使用无状态Hibernate会话。无状态会话没有第一级缓存,即没有持久性上下文。稍后,当您尝试迭代注释时,Hibernate将抛出异常。

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed

解决方案可以是:

使用fetch = FetchType注释注释。急切的 @OneToMany(fetch = FetchType。mappedBy = "topic", cascade = CascadeType.ALL) private Collection<Comment> comments = new LinkedHashSet<Comment>(); 如果您仍然希望延迟加载注释,请使用Hibernate的有状态会话,这样您就可以在需要时获取注释。

最好的解决方案之一是在应用程序中添加以下内容。属性文件: spring.jpa.properties.hibernate.enable_lazy_load_no_trans = true