不能加事务的场景
一、@Transactional 传播行为(重点 3 种)
1. REQUIRED(默认)
- 规则:当前有事务就加入,没有就新建事务,所有操作共享同一个事务。
- 场景:绝大多数普通增删改,单业务流程数据一致性保障。
- 特点:同一事务内,任意节点异常整体回滚。
2. REQUIRES_NEW
规则:强制新建独立事务,挂起当前已有事务,互不影响。
特点:
1.内层事务提交 / 回滚,不会影响外层事务;
2.外层异常回滚,内层已提交的数据保留。
适用:日志记录、独立埋点、必须落库的操作(哪怕主业务失败)。
3. NOT_SUPPORTED(你标注的无事务运行)
- 规则:强制以非事务方式运行,如果上层存在事务,会先挂起原有事务。
- 特点:方法内所有 DB 操作自动提交,异常不会回滚。
- 适用:查询操作、大数据量遍历、外部接口调用场景。
代码示例
importorg.springframework.transaction.annotation.Propagation;importorg.springframework.transaction.annotation.Transactional;// 默认 REQUIRED@TransactionalpublicvoidnormalBiz(){// 增删改,整体事务}// 新建独立事务@Transactional(propagation=Propagation.REQUIRES_NEW)publicvoidseparateLog(){// 独立事务,不受外层事务影响}// 无事务运行@Transactional(propagation=Propagation.NOT_SUPPORTED)publicvoidqueryOrCallOuter(){// 查询/调用第三方接口,无事务}二、不建议开启事务的场景(补充原因 + 避坑)
1.外部接口调用 + 批量 DB 操作
- 原因:接口调用网络耗时不确定,会造成长事务,锁表、占用数据库连接、引发死锁、超时。
- 方案:拆分为「先调用接口 → 再分批操作数据库」,DB 部分分批小事务。
2.大数据量 / 高频率定时任务
- 原因:全量数据放在一个事务中,事务体积过大,日志暴涨、回滚代价极高、容易事务超时。
- 方案:
- 关闭全局事务(
NOT_SUPPORTED); - 分页 / 分批处理,每批单独开小事务。
- 关闭全局事务(
3.额外补充禁忌场景
- 纯查询接口:没必要开启事务,增加开销,直接用
NOT_SUPPORTED。 - 循环内单次少量操作:长循环套大事务,极易长事务。
三、事务作用域 & 生效范围
核心结论
Spring 事务仅对当前方法内的 INSERT / DELETE / UPDATE 生效,查询(SELECT)本身不参与事务回滚逻辑。
边界说明
事务锁、数据回滚、隔离级别,只作用于被修改的数据表 / 行;不同库、不同表、跨库操作,默认无法统一事务(普通单库事务不支持跨库)。
常见误区
误区:加了事务,整个服务所有表都会被锁定。
纠正:仅本次增删改涉及的表 / 行受事务管控。
四、注意事项
1.事务失效经典场景
同类内部调用:
A方法(无事务)直接调用本类@Transactional B方法→事务失效(AOP 动态代理拦截不到)。方法非
public:private/protected 方法加注解 → 事务失效。异常类型:默认只捕获 RuntimeException/Error,检查型 Exception 不回滚。
解决:
@Transactional(rollbackFor = Exception.class)
2.NOT_SUPPORTED 注意点
上层有事务时,进入该方法原事务被挂起,方法执行完再恢复原事务;方法内报错,数据不会回滚。
3.REQUIRES_NEW 注意点
嵌套使用会产生事务挂起 / 恢复,数据库开销更大,不要滥用。
