两次事务中出现LazyInitializationException是否正常?重取实体是否为反模式?
问题解答
问题1:抛出LazyInitializationException是否属于正常行为?
这是完全正常的行为,核心原因在于事务边界的控制:
- 标注
@Transactional的get方法执行完毕后,事务会自动提交,对应的持久化上下文(EntityManager)随之关闭,此时获取到的Entity对象从持久态转为游离态——不再被ORM框架(如Hibernate)管理。 - 游离态实体的懒加载关联属性仅保存了代理对象,并未实际加载数据。当后续在
validate方法中访问这些属性时,没有活跃的事务和持久化上下文支持延迟加载操作,因此必然抛出LazyInitializationException。
控制器代码示例:
Entity entity = entityService.get(id) ... <some data binding, etc> ... entityService.validate(entity) <--- 此处抛出LazyInitializationException
问题2:在validate方法中重新获取该Entity是否属于反模式?
重新获取实体不属于反模式,反而在多数场景下是合理且稳妥的做法:
- 重新获取的实体处于新的持久化上下文中,能够正常访问所有懒加载关联,不会触发延迟加载异常。
- 重新获取能确保拿到数据库中的最新数据,避免使用游离态实体可能带来的脏数据问题。
需要注意的细节:
- 如果之前对游离态的
Entity做了业务修改,直接重新获取会覆盖这些修改,此时需要先调用entityManager.merge(entity)将修改合并到新的持久化上下文,再进行后续操作。 - 当然也有其他替代方案,比如:
- 扩展事务范围,让
get和validate处于同一个事务中(但不推荐过度扩大事务边界,可能引发性能问题) - 在
get方法中通过Fetch Join或Hibernate.initialize()提前初始化懒加载属性
- 扩展事务范围,让
- 但重新获取实体是最直接、低风险的解决方案,不属于反模式。
内容的提问来源于stack exchange,提问作者sunny
相关产品推荐
相关产品推荐

