我有这样一个问题:

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


当前回答

还有另一种方法,可以使用TransactionTemplate封装惰性获取。 就像

Collection<Comment> commentList = this.transactionTemplate.execute
(status -> topicById.getComments());

其他回答

在第二次执行生成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()));

为了延迟加载集合,必须有一个活动会话。在web应用中,有两种方法可以做到这一点。您可以使用Open Session In View模式,其中使用拦截器在请求开始时打开会话,并在结束时关闭会话。风险在于你必须有可靠的异常处理,否则你可能会绑定所有的会话,你的应用程序可能会挂起。

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. 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()). 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.

你的列表是惰性加载的,所以列表没有加载。 仅仅通过电话进入名单是不够的。 在Hibernate中使用。初始化以初始化列表。 如果不起作用,运行列表元素并调用Hibernate。初始化每一个。 这需要在从事务范围返回之前进行。 看看这篇文章。 搜寻-

Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session 

如果你试图在一个实体和一个集合或java对象的列表(例如长类型)之间有一个关系,它会像这样:

@ElementCollection(fetch = FetchType.EAGER)
    public List<Long> ids;

为了解决这个问题,在我的例子中,它只是少了这一行

<tx:annotation-driven transaction-manager="myTxManager" />

在应用程序上下文文件。

方法上的@Transactional注释没有考虑在内。

希望这个答案能帮助到一些人