标注@Transactional仍触发LazyInitializationException:事务未传播?
问题:事务传播异常导致延迟加载失败(测试环境正常,生产环境失效)
标注了@Transactional的方法,事务未在嵌套方法中传播,引发LazyInitializationException。奇怪的是,通过@SpringBootTest进行集成测试时延迟加载正常,但Spring Boot 3.3.2部署环境中处理HTTP请求时却失效。
实体映射
@Entity public class VtBsoEntity { @Id private UUID id; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "arriving_train_id", referencedColumnName = "id") private VtTrainEntity arrivingTrain; @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "leaving_train_id", referencedColumnName = "id") private VtTrainEntity leavingTrain; // 其他字段与方法 } @Entity public class VtTrainEntity { @Id private UUID id; private Integer trainNo; // 其他字段与方法 }
REST控制器入口
@RestController public class TemplateMetadataController { private final TemplateMetadataService service; public TemplateMetadataController(TemplateMetadataService service) { this.service = service; } public ResponseEntity<List<GetTemplateMetadataDto>> findAllTemplates() { final List<TemplateMetadataModel> templates = service.findAll(); // 堆栈跟踪中的失败点 // 后续逻辑 return ResponseEntity.ok(...); } // 其他方法 }
TemplateMetadataService代码
@Service public class TemplateMetadataService { private final NumberCalculatorService numberCalculatorService; public TemplateMetadataService(NumberCalculatorService numberCalculatorService) { this.numberCalculatorService = numberCalculatorService; } @Transactional(isolation = Isolation.READ_COMMITTED, readOnly = true) public List<TemplateMetadataModel> findAll() { // 查询逻辑 return mapToModel(); } private TemplateMetadataModel mapToModel(TemplateMetadataEntity entity) { // 映射逻辑 numberCalculatorService.getNumberModel(entity); // 堆栈跟踪中的失败点 // 返回模型 return ...; } }
NumberCalculatorService代码
@Service public class NumberCalculatorService { private final VtBsoEntityRepository vtBsoEntityRepository; public NumberCalculatorService(VtBsoEntityRepository vtBsoEntityRepository) { this.vtBsoEntityRepository = vtBsoEntityRepository; } public AggregateBsoNumberModel getNumberModel(TemplateMetadataEntity entity) { List<VtBsoEntity> bsoList = vtBsoEntityRepository .findAllByMuWoIdAndActive(entity.getId(), true); bsoList.getFirst().getArrivingTrain(); // LazyInitializationException,无会话 // 后续逻辑 return ...; } }
问题分析:为什么NumberCalculatorService中持久化上下文丢失?
1. 测试与生产环境的事务上下文差异
测试时,@SpringBootTest会通过TransactionalTestExecutionListener为整个测试方法创建全局事务,EntityManager在测试全程保持打开状态,所有DAO操作共享同一个持久化上下文,延迟加载自然正常。而部署环境中,只有TemplateMetadataService.findAll()方法带有事务,若事务上下文未正确传递到NumberCalculatorService.getNumberModel(),会导致vtBsoEntityRepository的查询脱离原事务,查询完成后EntityManager立即关闭,实体变为游离态,触发延迟加载异常。
2. 事务传播的隐性失效
尽管默认传播行为是Propagation.REQUIRED(加入当前事务),但以下情况会导致传播失效:
NumberCalculatorService未通过Spring容器注入(比如手动new实例),事务代理未生效;- AOP切面优先级冲突,事务切面未覆盖跨Bean调用逻辑;
- Spring Boot 3.3.2的事务管理器配置调整,导致
PlatformTransactionManager未正确绑定JPA的EntityManagerFactory,事务上下文无法跨Bean传递。
3. 事务提前提交或异步调用
若TemplateMetadataService.findAll()方法中,调用mapToModel()前执行了EntityManager.flush()等操作,或mapToModel()的调用处于异步线程中,会导致原事务提前关闭或事务上下文无法传递到异步线程,使得getNumberModel()中的实体变为游离态。
解决方案
- 给
NumberCalculatorService.getNumberModel()添加@Transactional(propagation = Propagation.REQUIRED, readOnly = true)注解,强制该方法加入当前事务,确保查询的实体处于托管状态; - 检查
NumberCalculatorService的注入方式,确保由Spring容器管理,避免手动实例化; - 验证生产环境的事务管理器配置,确保
JpaTransactionManager正确关联EntityManagerFactory; - 排查是否存在异步调用,若有则使用
@Transactional(propagation = Propagation.REQUIRES_NEW)或手动传递事务上下文。
内容的提问来源于stack exchange,提问作者kladderradatsch
相关产品推荐
相关产品推荐

