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() 它会起作用,但这不是解决方案。
希望有人能帮助我。谢谢。
解决方案
- 删除所有手工交易
- 添加事务注释
- 用户 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();
}
当我尝试检索 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() 它会起作用,但这不是解决方案。
希望有人能帮助我。谢谢。
解决方案
- 删除所有手工交易
- 添加事务注释
- 用户 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();
}