事务失效十大场景分析
1. 方法不是 public最经典失效代码示例ServicepublicclassUserService{AutowiredprivateUserMapperuserMapper;// 非 public → 事务失效TransactionalprivatevoidaddUser(){userMapper.insert(newUser(张三));// 模拟异常inti1/0;}publicvoidcallAdd(){addUser();}}原理分析Spring 事务基于AOP 动态代理代理逻辑只拦截public 方法private/protected/default方法会被 Spring 直接忽略Transactional结果数据库插入成功没有回滚事务完全失效。解决方法改为publicTransactionalpublicvoidaddUser(){...}2. 同类内部方法调用this.方法()代码示例ServicepublicclassUserService{AutowiredprivateUserMapperuserMapper;// 无事务publicvoidouter(){// this 调用 → 不走代理 → 事务失效this.inner();}// 有事务Transactionalpublicvoidinner(){userMapper.insert(newUser(李四));inti1/0;}}原理分析Transactional生效必须走代理对象同类内部this.method()调用的是原始对象绕过代理AOP 增强逻辑完全不执行结果数据插入成功不回滚。解决方案 1注入自身代理推荐ServicepublicclassUserService{AutowiredprivateUserServiceuserService;// 注入自己publicvoidouter(){userService.inner();// 走代理}Transactionalpublicvoidinner(){...}}解决方案 2使用 AopContext// 启动类开启暴露代理EnableAspectJAutoProxy(exposeProxytrue)// 调用((UserService)AopContext.currentProxy()).inner();3. 异常被 try-catch 吃掉不抛出代码示例ServicepublicclassUserService{AutowiredprivateUserMapperuserMapper;TransactionalpublicvoidaddUser(){try{userMapper.insert(newUser(王五));inti1/0;}catch(Exceptione){// 异常被吞 → Spring 不知道出错}}}原理分析Spring 事务通过捕获异常触发回滚你 catch 后不抛Spring 认为执行成功执行commit结果数据入库不回滚。解决不要吞异常或手动标记回滚catch(Exceptione){// 方式1继续抛出thrownewRuntimeException(e);// 方式2手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}4. 默认只回滚 RuntimeException抛出 Exception 不回滚代码示例Transactionalpublicvoidtest()throwsException{userMapper.insert(...);// 受检异常 Exception → 默认不回滚thrownewException(出错);}原理分析Spring 默认规则✅RuntimeException/Error→ 回滚❌Exception受检异常→不回滚直接提交结果数据插入成功。解决指定回滚异常类型Transactional(rollbackForException.class)5. 多线程 / 异步方法新线程脱离事务代码示例Transactionalpublicvoidtest(){userMapper.insert(...);// 主线程事务内newThread(()-{// 新线程独立连接不在当前事务里userMapper.insert(...);inti1/0;}).start();}原理分析Spring 事务与ThreadLocal绑定新线程不共享事务上下文使用独立数据库连接主线程回滚不影响子线程结果子线程数据插入成功不回滚。解决不要在事务内开线程使用分布式事务Seata异步方法自己加事务控制6. 数据库引擎不支持事务MyISAM代码示例CREATETABLEuser(idINTPRIMARYKEY)ENGINEMyISAM;-- 不支持事务Transactionalpublicvoidtest(){userMapper.insert(...);inti1/0;}原理分析代码层面事务生效但存储引擎不支持回滚InnoDB 支持事务MyISAM 不支持结果插入成功不回滚。解决ALTERTABLEuserENGINEInnoDB;7. 类没有被 Spring 管理自己 new 对象代码示例// 没加 ServicepublicclassUserService{Transactionalpublicvoidadd(){...}}ControllerpublicclassUserController{publicvoidtest(){// 自己 new → 不受 Spring 管理UserServiceservicenewUserService();service.add();}}原理分析只有 Spring 管理的 Bean 才会生成代理手动 new 的对象没有 AOP 增强结果事务失效。解决加上Service并使用Autowired注入。8. 事务传播行为设置错误代码示例Transactional(propagationPropagation.NOT_SUPPORTED)publicvoidtest(){userMapper.insert(...);inti1/0;}常见坑传播级别NOT_SUPPORTED非事务执行NEVER有事务就抛异常SUPPORTS无事务则非事务运行结果无事务不回滚。解决使用默认Transactional// 等价 REQUIRED9. final / static 方法 → 无法被代理代码示例Transactionalpublicfinalvoidtest(){...}Transactionalpublicstaticvoidtest2(){...}原理分析动态代理需要重写方法final 方法不能被重写static 属于类不属于实例无法代理结果事务失效。解决去掉final/static。10. 未开启事务注解驱动老项目常见代码示例// 启动类没加EnableTransactionManagement原理分析不开启则 Spring 不识别Transactional相当于注解无效解决SpringBootApplicationEnableTransactionManagementpublicclassApp{...}一张表总结所有失效场景场景是否生成代理是否触发回滚根本原因非 public否否不拦截内部 this 调用否否绕过代理异常被 catch是否无异常信号抛 Exception是否默认不回滚多线程是子线程否线程隔离MyISAM是否引擎不支持自己 new 对象否否非 Spring Bean传播行为错误是否策略不开启事务final/static否否无法重写未开启 Enable…否否事务未启用
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2470078.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!