Spring Boot控制台应用中Hibernate LazyInitializationException异常疑问
核心原因
Spring Data JPA的Repository方法默认自带事务,在没有外层事务的情况下,Repository方法执行完成后,事务会立即提交,对应的EntityManager会被释放回连接池。此时即使Session对象本身未关闭,它也已经和当前执行线程的上下文解绑,Hibernate会在EntityManager清理阶段主动调用unsetSession,清空所有已加载实体关联懒加载集合的Session引用——这是Hibernate为了避免内存泄漏、保证懒加载仅在事务范围内生效的内部机制。
为什么Session看起来还打开但无法用
Spring管理的Hibernate Session是和事务绑定的,事务提交后Session不会立刻销毁(连接池复用策略),但它不再属于当前执行上下文。懒加载集合的触发需要依赖当前线程绑定的有效Session上下文,而不是单纯的Session对象是否打开,所以此时访问懒加载集合会抛出LazyInitializationException。
加@Transactional解决的原理
当给foo方法添加@Transactional注解后,整个方法会处于一个统一的事务上下文内:Repository方法调用会复用这个外层事务,不会在Repository执行完毕后提交事务,EntityManager始终和当前线程绑定,懒加载集合的Session引用不会被清空,访问集合时能正常获取到有效Session完成懒加载。
控制台应用的特殊性
不同于Web应用的Open Session in View机制,控制台应用没有默认的全局事务上下文扩展,事务仅在单个Repository方法或标注了@Transactional的方法范围内生效,超出这个范围后懒加载就会失去有效Session支持。
内容的提问来源于stack exchange,提问作者Alexander

