Spring + 休眠:LazyInitializationException

Spring + Hibernate : LazyInitializationException

当我尝试检索 POJO 中的信息时出现 LazyInitializationException。

User.java

public class User  implements java.io.Serializable {

 private Set groups = new HashSet(0);

    public Set getGroups() {
       return this.groups;
   }

}

UserController.java

@RequestMapping(value = "/home", method = RequestMethod.GET)
public ModelAndView getHome(HttpServletRequest request) throws Exception {
    ModelAndView mv;
    User user = SessionUtil.getSessionUser(request);
    if (user == null) {
        mv = new ModelAndView("redirect:/user/login");
    } else {
        mv = new ModelAndView("home");
        user = this.userService.getUserById(user.getId());

        // Exception here 
        Set<Group> groups = user.getGroups();
        mv.addObject("groups", groups);

        // This work fine
        List<Group> invitation_groups = this.userService.getInvitationGroups(user);
        mv.addObject("invitation_groups", invitation_groups);

        // This work fine
        List<Group> subscription_groups = this.userService.getSubscriptionGroups(user);
        mv.addObject("subscription_groups", subscription_groups);

    }

    return mv;
}

数据库

=====
-用户-
编号
登录

=====
-组-
编号
用户(用户的外键)


at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at model.pojo.User_$$_jvst464_2.getGroups(User_$$_jvst464_2.java)
at controller.UserController.getHome(UserController.java:151)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

我想我明白为什么会出现此异常:我总是在我的 DAO 中完成所有事务后关闭 HibernateSession,因此无法为 POJO 请求打开会话。

另一方面,user.getLogin() 例如有效。我想我不太明白问题出在哪里。那是因为它使用外键吗?

我想我找到了解决方法 here 但我不知道如何实施它以及它是否真的有效。

我知道如果我从我的 DAO 中删除 session.close() 它会起作用,但这不是解决方案。

希望有人能帮助我。谢谢。

解决方案

  1. 删除所有手工交易
  2. 添加事务注释
  3. 用户 OpenSessionInView 过滤器。

谢谢大家。

为什么要手动处理会话?你需要那个吗?

如果没有,您应该使用 OpenSessionInView 模式。它会让您的会话保持打开状态,直到请求结束,但是,请注意,由于集合的延迟加载,您可能 运行 因对数据库进行大量查询而遇到麻烦。因此,只要有可能,如果您知道数据将被使用,请尝试热切地获取数据。

你的user.getLogin()returns一个字符串对吗?就算是关系映射的一侧,也会默认急切获取。

我不习惯 spring,但我认为 spring 有一个 OpenSessionInView 过滤器来管理您的会话。

在API层处理事务并使用DTO是正常的, 所以你有:API -> 服务 -> DAO。

但是由于您在 DAO 中只有事务,所以它可能还可以,但是您必须在事务关闭之前处理 DAO 中的延迟加载对象。

// 在此之后事务打开和关闭,用户对象是休眠 jpa 实体,您通常会得到这个。
用户 = this.userService.getUserById(user.getId());

最简单的解决方案是在返回用户之前循环并在 DAO 中执行 getId()。

Set<Group> groups = user.getGroups();

 for (Group group in groups){
   group.getId(); 
}