标注@Transactional后仍出现Hibernate懒加载初始化失败异常原因
加了@Transactional仍触发懒加载初始化异常的原因
这个问题的核心本质是:你访问懒加载集合的代码执行时机,已经脱离了Hibernate Session的有效生命周期,和方法上标注了@Transactional并不矛盾,对应你场景的常见触发原因如下:
- Controller层的@Transactional默认不生效
Spring默认的事务代理切面只会拦截@Service、@Repository这类业务层Bean的公共方法,不会对Controller层的@PostMapping标注的请求处理方法做事务增强。你把@Transactional加在Controller方法上,没有额外自定义切面配置的话,这个方法根本不会开启事务,也就没有绑定到事务上下文的Hibernate Session,自然无法完成懒加载集合的初始化。 - Service方法的事务提前提交,返回的实体已经脱管
就算你调整配置让Controller层的事务生效,你调用的someService.assignSomething()如果配置了独立事务(比如事务传播级别设为REQUIRES_NEW),这个方法执行完就会提交自身事务、关闭对应的Session。此时返回的createdEntities里的实体已经是脱管状态,后续你做非空判断、调用anotherService.publishPackageDataChangeEvent触发下游逻辑时,只要代码访问到实体上未初始化的懒加载关联字段,就会抛出no Session错误。 - 事件监听逻辑不在事务生效范围内
从异常栈能看到,实际触发懒加载的位置是aThirdService.thingsChanged,也就是事件发布后的监听逻辑。如果你的事件是异步发送(标注了@Async)、或者监听配置为事务提交后才执行(比如用了@TransactionalEventListener(phase = AFTER_COMMIT)),等监听逻辑真正运行时,原事务早就提交完成、Session已经关闭,这时候访问懒加载字段必然报错。
排查&修复方案
- 不要在Controller层加事务注解,把@Transactional挪到实际操作数据库的Service层公共方法上,保证事务AOP能正常生效。
- 检查
assignSomething方法的事务传播配置,用默认的REQUIRED级别即可,让它加入外层事务,保证Session的生命周期能覆盖到后续需要使用实体的逻辑。 - 如果事件逻辑确实要在事务提交后执行、或者异步执行,不要直接传递持久化实体对象:在事务未关闭时提前把需要用到的懒加载字段初始化(比如手动调用关联集合的
size()触发加载,或者把字段提取成DTO再传递),杜绝在事务外访问脱管实体的懒加载属性。 - 快速验证方法:在Service层方法return之前,手动访问一次报错的关联集合触发初始化,如果异常消失,就能确认是Session生命周期没有覆盖到懒加载访问时机的问题。
额外提一句:你贴的代码里有个变量拼写笔误,if判断里写的是
createdEntties,和上方定义的createdEntities变量名差了一个字母,虽然和本次异常无关,但会直接导致编译失败,建议一起改掉。
内容的提问来源于stack exchange,提问作者serv-inc
相关产品推荐
相关产品推荐

