2020-10-25 05:44:21
导致@Transactional声明式事务失效的7大典型场景及原因、解决方案如下:
方法访问修饰符非public
原因:Spring AOP代理生成事务代理时,仅对public方法生效。源码中computeTransactionAttribute方法会检查方法修饰符,非public方法直接返回null,导致事务不生效。
示例:
@Servicepublic class OrderService { @Transactional private void createOrder() { // 事务失效 // ... }}解决方案:将方法修饰符改为public。
自调用问题
原因:类内部非事务方法直接调用事务方法(通过this),绕过Spring代理对象,事务无法生效。
示例:
@Servicepublic class OrderService { public void placeOrder() { createOrder(); // 直接调用,事务失效 } @Transactional public void createOrder() { // ... }}解决方案:
将事务方法移至其他Service类。
通过ApplicationContext获取代理对象调用:
@Autowiredprivate ApplicationContext context;public void placeOrder() { OrderService proxy = context.getBean(OrderService.class); proxy.createOrder(); // 通过代理调用}异常被捕获且未重新抛出
原因:Spring默认仅对未捕获的RuntimeException或Error回滚事务。若异常被捕获且未抛出,代理认为方法执行成功,提交事务。
示例:
@Transactionalpublic void transferMoney() { try { addMoney(); } catch (Exception e) { log.error("异常", e); // 捕获未抛出,事务不回滚 }}解决方案:
手动设置回滚:
catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}重新抛出异常:
catch (Exception e) { throw e; // 或仅setRollbackOnly}事务传播机制配置错误
原因:错误使用传播行为(如Propagation.NOT_SUPPORTED挂起事务、Propagation.NEVER拒绝事务)会导致事务失效。Propagation.REQUIRES_NEW会开启新事务,需谨慎避免嵌套事务问题。
示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED) // 事务挂起public void process() { // ...}解决方案:根据业务需求选择正确的传播行为(如默认Propagation.REQUIRED)。
数据库引擎不支持事务
原因:底层数据库引擎未开启事务支持(如MySQL使用MyISAM引擎)。即使代码配置@Transactional,也无法实现事务。
示例:MySQL的MyISAM引擎不支持事务,需切换为InnoDB。
解决方案:确认数据库引擎支持事务(如InnoDB、PostgreSQL等)。
方法被final或static修饰
原因:CGLIB无法代理final方法(不可重写),JDK动态代理无法处理static方法,导致事务失效。
示例:
@Servicepublic class OrderService { @Transactional public final void createOrder() { // final方法,事务失效 // ... }}解决方案:移除final或static修饰符。
多线程中调用事务方法
原因:事务基于线程绑定(通过ThreadLocal存储上下文),子线程无法继承父线程的事务上下文。
示例:
@Transactionalpublic void process() { new Thread(() -> { dao.update(); // 子线程无事务 }).start();}解决方案:
使用事务同步机制(如Spring的TransactionSynchronizationManager)。
手动管理事务(如编程式事务TransactionTemplate)。
总结:@Transactional失效的核心原因多与Spring AOP代理机制相关(如方法修饰符、自调用、代理限制),或与事务基础支持(如数据库引擎、线程绑定)有关。掌握这些场景可避免常见陷阱,提升代码健壮性。