从 Spring MVC @Controller 获取集合时的 HIbernate 延迟加载行为
HIbernate lazy-loading behaviour when fetching collections from Spring MVC @Controller
假设我在 Spring MVC @Controller
中有以下方法:
@RequestMapping(value = "/list")
public ModelAndView renderView(@PathVariable("id") int id, @ModelAttribute("someForm") SomeForm someForm) {
SomeEntity someEntity = someEntityService.findById(id);
someForm.setEntity(someEntity);
someForm.setLstFromEntity(
new ArrayList<SomeSubEntity>(someEntity.getSomeSubEntities())
);
return new ModelAndView("someView", "someForm", someForm);
}
someEntityService
是一个 @Transactional
@Service
并且我正在获取它的集合是延迟加载的所以认为获取会失败是有道理的,因为没有会话处于活动状态(我不确定这是不是真的)。不过抓取效果很好。
但是,我有另一种注释为 @RequestMapping(value = "/save")
的方法,它执行保存并调用 renderView()
到 return 客户端视图。
在这种情况下,someEntity.findById(id)
return 是实体,但不会向数据库触发任何 select。所有字段都已填充,但集合 (PersistentBag) 为空,因此实体不完整。
几个问题:
- 会话真的关闭了吗?
- 第二种情况下这个someEntity是从哪里来的?
- 为什么集合 return 变空了?
好的,我认为这个问题没有得到解答的原因是缺乏信息。当我保存 SomeSubEntity 的 new 实例时,我使用两个 ID 来定义它与模型的另一个实体的两个关系。
new SomeSubEntity(foo1Id, foo2Id);
并且 SomeSubEntity 的构造函数执行如下操作:
public SomeSubEntity(Integer idFoo1, Integer idFoo2) {
this.setFoo1(new Foo1(idFoo1));
this.setFoo2(new Foo2(idFoo2));
}
Foo1
/Foo2
的构造函数只设置指定的 ID。
foo1Id
和 foo2Id
匹配 Foo1
和 Foo2
两个实体的两个 ID 已经保存在数据库中并通过外键与 SomeSubEntity
相关(和 Hibernate 映射),因此事务成功完成。
但是,似乎保留在会话中的 Foo1
和 Foo2
的实体与创建的实体相同(仅 ID,没有从数据库更新),所以当我得到一个属性 从他们那里,返回默认 class 值而不是数据库中的实际值。
我使用数据库中的托管实体解决了这个问题,而不是创建一个具有匹配 ID 的新实体:
public SomeSubEntity(Foo1 foo1, Foo2 foo2) {
this.setFoo1(foo1);
this.setFoo2(foo2);
}
new SomeSubEntity(
foo1DAO.findById(idFoo1),
foo2DAO.findById(idFoo2)
);
缺点是查询(显然)被触发到数据库。
假设我在 Spring MVC @Controller
中有以下方法:
@RequestMapping(value = "/list")
public ModelAndView renderView(@PathVariable("id") int id, @ModelAttribute("someForm") SomeForm someForm) {
SomeEntity someEntity = someEntityService.findById(id);
someForm.setEntity(someEntity);
someForm.setLstFromEntity(
new ArrayList<SomeSubEntity>(someEntity.getSomeSubEntities())
);
return new ModelAndView("someView", "someForm", someForm);
}
someEntityService
是一个 @Transactional
@Service
并且我正在获取它的集合是延迟加载的所以认为获取会失败是有道理的,因为没有会话处于活动状态(我不确定这是不是真的)。不过抓取效果很好。
但是,我有另一种注释为 @RequestMapping(value = "/save")
的方法,它执行保存并调用 renderView()
到 return 客户端视图。
在这种情况下,someEntity.findById(id)
return 是实体,但不会向数据库触发任何 select。所有字段都已填充,但集合 (PersistentBag) 为空,因此实体不完整。
几个问题:
- 会话真的关闭了吗?
- 第二种情况下这个someEntity是从哪里来的?
- 为什么集合 return 变空了?
好的,我认为这个问题没有得到解答的原因是缺乏信息。当我保存 SomeSubEntity 的 new 实例时,我使用两个 ID 来定义它与模型的另一个实体的两个关系。
new SomeSubEntity(foo1Id, foo2Id);
并且 SomeSubEntity 的构造函数执行如下操作:
public SomeSubEntity(Integer idFoo1, Integer idFoo2) {
this.setFoo1(new Foo1(idFoo1));
this.setFoo2(new Foo2(idFoo2));
}
Foo1
/Foo2
的构造函数只设置指定的 ID。
foo1Id
和 foo2Id
匹配 Foo1
和 Foo2
两个实体的两个 ID 已经保存在数据库中并通过外键与 SomeSubEntity
相关(和 Hibernate 映射),因此事务成功完成。
但是,似乎保留在会话中的 Foo1
和 Foo2
的实体与创建的实体相同(仅 ID,没有从数据库更新),所以当我得到一个属性 从他们那里,返回默认 class 值而不是数据库中的实际值。
我使用数据库中的托管实体解决了这个问题,而不是创建一个具有匹配 ID 的新实体:
public SomeSubEntity(Foo1 foo1, Foo2 foo2) {
this.setFoo1(foo1);
this.setFoo2(foo2);
}
new SomeSubEntity(
foo1DAO.findById(idFoo1),
foo2DAO.findById(idFoo2)
);
缺点是查询(显然)被触发到数据库。