当前位置: 首页 > news >正文

@Transactional 原理与事务失效场景

一句话

@Transactional 基于 AOP 动态代理,通过 TransactionInterceptor 在方法前后开启/提交/回滚事务。自调用绕过代理、异常被吞、非 public 方法等 6 个场景会导致事务失效。


1. 底层原理

Controller 调用 userService.save() ↓ 实际调用的是 userService 的代理对象(AOP 动态代理生成的) ↓ 代理对象先走 TransactionInterceptor(事务拦截器) ↓ ① 开启事务(从连接池拿连接 → conn.setAutoCommit(false)) ↓ ② 执行真实方法 save() ↓ ③ 正常结束 → commit() 抛异常 → rollback()

三个核心角色:

角色职责
PlatformTransactionManager事务管理器,负责 begin / commit / rollback
TransactionInterceptor事务拦截器,AOP 切面的具体执行者
@Transactional标记注解,告诉 Spring 哪些方法需要事务增强

PlatformTransactionManager 由 Spring Boot 自动配置创建(引入 DataSource + spring-tx 依赖即可)。


2. 事务失效的 6 个高频场景

场景 1:自调用(最常考)

@ServicepublicclassUserService{@TransactionalpublicvoidmethodA(){// 操作数据库...this.methodB();// ← this 调用,绕过代理对象}@TransactionalpublicvoidmethodB(){// 操作数据库...}}

this.methodB()调用的是原始对象,不是代理对象,TransactionInterceptor 没机会拦截。

解决:

① 把 methodB 抽到另一个 Service 类(走代理) ② 注入自己:@Autowired private UserService self; self.methodB();

场景 2:方法不是 public

@Transactionalprivatevoidsave(){// Spring AOP 只拦截 public 方法// 操作数据库}

场景 3:异常被 catch 吞掉

@Transactionalpublicvoidsave(){try{// 操作数据库}catch(Exceptione){log.error("出错了",e);// 异常被吞,代理以为正常结束,走 commit}}

代理对象只会在方法抛异常时触发 rollback。catch 吞了异常,代理不知道出错了。

解决:catch 里重新 throw,或手动标记回滚:

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

场景 4:异常类型不匹配

@Transactional// 默认 rollbackFor = RuntimeExceptionpublicvoidsave()throwsIOException{thrownewIOException("文件错误");// 检查异常,不回滚}

默认只对 RuntimeException 和 Error 回滚。IOException、SQLException 等检查异常不会触发回滚。

解决:@Transactional(rollbackFor = Exception.class)

场景 5:类没交给 Spring 管理

publicclassUserService{// 没有 @Service@Transactionalpublicvoidsave(){// 自己 new 出来的对象没有代理对象}}

场景 6:传播级别不对

@Transactional(propagation=Propagation.NOT_SUPPORTED)publicvoidsave(){// 明确说了不支持事务}

3. 传播级别 vs 隔离级别

面试容易混的两个概念:

传播级别 propagation:这个方法和已有事务是什么关系 REQUIRED(默认):有事务就加入,没有就新建 REQUIRES_NEW:挂起已有事务,新建独立事务 NOT_SUPPORTED:明确不要事务 SUPPORTS:有事务就加入,没有就非事务执行 MANDATORY:必须在事务中调用,否则抛异常 NEVER:必须不在事务中调用,否则抛异常 NESTED:嵌套事务(子事务回滚不影响父事务) 隔离级别 isolation:事务之间互相隔离的程度 READ_UNCOMMITTED → 脏读 READ_COMMITTED → 不可重复读(MySQL 默认) REPEATABLE_READ → 幻读(InnoDB 默认) SERIALIZABLE → 串行化

传播级别影响"事务是否生效",隔离级别影响"并发读写是否安全"。不要混。


4. @Transactional 常用属性

@Transactional(propagation=Propagation.REQUIRED,// 传播级别isolation=Isolation.DEFAULT,// 隔离级别(用数据库默认)timeout=30,// 超时秒数readOnly=false,// 是否只读rollbackFor=Exception.class,// 指定回滚异常类型noRollbackFor=NullPointerException.class// 指定不回滚异常类型)

面试回答模板

"@Transactional 底层基于 AOP 动态代理。调用带 @Transactional 注解的方法时, 实际执行的是代理对象,代理对象通过 TransactionInterceptor 在方法前开启事务, 方法正常结束 commit,抛异常 rollback。 事务失效最常见的是自调用:同一个类里 this.method() 绕过了代理对象, TransactionInterceptor 没机会拦截,事务不生效。 其他常见场景包括:方法不是 public、异常被 catch 吞掉、 异常类型不匹配(默认只回滚 RuntimeException)、 类没交给 Spring 管理、传播级别设为 NOT_SUPPORTED。 这里要注意传播级别和隔离级别是两个不同概念: 传播级别控制方法和已有事务的关系,隔离级别控制并发读写的隔离程度。"

参考来源

  • Day11-Spring 与 SpringBoot
  • 01_Raw【原始素材】/面试资料-B站博主/Spring篇(13题) - 飞书云文档.md
http://www.jsqmd.com/news/1195887/

相关文章:

  • DS90UB949A-Q1 FPD-Link III串行器I2C配置与硬件设计实战指南
  • MMDetection(简称 mmdet)是 OpenMMLab 开发的开源目标检测框架,基于 PyTorch 构建
  • Java NIO内存管理机制剖析
  • 效率的馈赠与创意的觉醒:AI时代的人文主义复兴
  • HarmonyOS7居中吸附对比页实战:ScrollSnap Center 模式的强化展示
  • 几百台电脑补丁、权限、故障都靠人工?运维该看的管理面
  • Java Comparator接口实战:解锁Arrays.sort()的多维度排序策略
  • 深入解析SM320C6748-HIREL SPI模块:从时序参数到多从机系统设计
  • Spring Boot 之 BeanDefinitionLoader 详解
  • 2026 录音转会议纪要APP推荐:成本分析后只留这个不踩雷
  • 飘柔甜美花漾洗发水实测:香氛持久与柔亮效果深度解析
  • ultralytics-yolo的训练、预测、export内部流程图
  • C++标准库与C++11实战指南:从容器算法到智能指针与移动语义
  • 高速信号完整性:重定时器(Retimer)原理、配置与实战调试指南
  • 一文讲清人才培养:从选人、育人到用人的5步闭环
  • C++ COM组件开发实战:ATL/WTL实现跨语言对话框的完整指南
  • 阿里云云监控 CMS 2.0 推 Session Replay 与热力图:穿透前端迷雾,优化用户体验
  • 绍兴上虞区打井多少钱一米,上虞打井电话,软土平原打井找谁 - 瑞溪泉水利
  • C++ WebSocket++库实战:构建高性能实时通信应用
  • 双指针算法精解:从盛水容器到LeetCode高频题实战
  • 折叠式共源共栅运算放大器:从理论到实践的设计指南
  • Python多因子选股模型:从因子挖掘到机器学习策略回测实战
  • Arduino作为ROS小车硬实时执行器的设计与实现
  • 【Java踩坑笔记】45_日志打印对象用toString,生产环境可能引发雪崩
  • 深入解析TI C6748 DSP:架构、开发与优化实战指南
  • MATLAB中FFT频谱分析实战:从基础语法到频谱泄露与补零策略
  • TensorFlow 是由 Google 开发并开源的端到端开源机器学习框架,广泛用于构建和训练深度学习模型(如神经网络)
  • 2026年7月最新亨得利官方服务项目及价格查询|服务热线及门店地址权威信息通知 - 亨得利官方博客
  • LT8710控制器解决长距离电源线电压降问题
  • 撒尿的小孩,蚂蚁,以及沉默的天气——论人类认知的三重牢笼