欢迎光临
我们一直在努力

Spring @Transactional 事务失效7大坑点,你踩过几个?

一、事务失效的 7 大核心场景

1. 注解标注在非 public 方法上

  • 失效原因:Spring 事务基于 AOP 动态代理实现,而代理机制仅对 public 方法生效。若将 @Transactional 加在 private/protected/ 默认权限(default)方法上,Spring 不会识别该注解,事务直接失效。
  • 解决方案:确保加 @Transactional 的方法为 public 权限,且避免用 final/static 修饰(CGLIB 代理无法处理)。

2. 同类内部方法互相调用

  • 失效原因:A 方法调用同一个类中的 B 方法(B 加 @Transactional),调用时走的是 this 原对象,而非 Spring 生成的代理对象,注解无法被解析,事务失效(最易踩坑的场景之一)。
  • 解决方案:
    • 方案 1(推荐):将 B 方法抽离到独立的 Service 类中,通过注入调用;
    • 方案 2:在当前类中注入自身代理对象(如通过 ApplicationContext 获取),用代理对象调用 B 方法;
    • 方案 3:使用 AspectJ 静态代理替代默认动态代理(成本较高,不推荐)。

3. 异常被捕获且未抛出 / 未指定回滚类型

  • 失效原因:
    • Spring 事务默认仅对 RuntimeException 和 Error 触发回滚,普通 Exception 不回滚;
    • 开发中常出现 try-catch 捕获异常后仅打日志不抛出自定义异常,事务感知不到异常,直接提交(典型案例:转账业务中异常被吞,导致单边扣钱)。
  • 解决方案:
    • 方案 1:catch 块中手动抛出运行时异常(如 throw new RuntimeException(e));
    • 方案 2:注解指定回滚所有异常:@Transactional(rollbackFor = Exception.class);
    • 方案 3:catch 块中手动触发回滚:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();。

4. 事务传播机制配置错误

  • 失效原因:@Transactional 的 propagation 参数(默认 REQUIRED:有事务则加入,无则新建)若配置错误,会导致事务逻辑异常:
    • 配置 REQUIRES_NEW:内层事务独立提交,外层回滚时内层已提交,数据不一致;
    • 配置 NOT_SUPPORTED:直接禁用事务,所有操作无事务保护;
    • 配置 NEVER/SUPPORTS 等不符合业务预期的传播级别。
  • 解决方案:不懂传播机制时保持默认 REQUIRED,仅在明确需要 “嵌套事务”“独立事务” 时调整,且需充分测试。

5. 数据库引擎不支持事务

  • 失效原因:MySQL 的 MyISAM 引擎不支持事务,仅 InnoDB 支持;若表引擎为 MyISAM,即便注解配置正确,事务也完全失效(老项目高频坑点)。
  • 解决方案:
    • 检查表引擎:SHOW CREATE TABLE 表名;;
    • 将表引擎改为 InnoDB:ALTER TABLE 表名 ENGINE = InnoDB;;
    • 新项目初始化时统一指定引擎为 InnoDB(如 MySQL 8.0 后默认 InnoDB,可忽略)。

6. 多数据源未指定事务管理器

  • 失效原因:项目配置多数据源时,@Transactional 默认绑定主数据源的事务管理器,若操作从库 / 其他数据源且未指定对应事务管理器,事务无法生效(微服务架构高频问题)。
  • 解决方案:注解中指定事务管理器:

    @Transactional(transactionManager = "slaveTransactionManager")

7. 类未被 Spring 容器管理

  • 失效原因:
    • 类未加 @Service/@Component/@Repository 等注解,未被 Spring 扫描并创建代理对象;
    • 手动 new 对象(如 new UserService()),而非通过 Spring 注入,导致注解无法被解析。
  • 解决方案:
    • 确保事务类被 Spring 注解标记,且在扫描包范围内;
    • 所有对象通过 @Autowired/@Resource 注入,禁止手动 new 事务类。

二、事务失效快速排查技巧

1. 日志排查(最有效)

在 application.yml/application.properties 中开启事务 debug 日志,可清晰看到事务的开启、提交、回滚过程:

logging:
level:
org.springframework.transaction: DEBUG
org.springframework.jdbc.datasource.DataSourceTransactionManager: DEBUG

日志中出现 Creating new transaction 表示事务生效,无该日志则说明事务未触发。

2. 快速自检清单

  • 事务方法是否为 public?
  • 是否存在同类内部方法调用?
  • 异常是否被吞、是否指定 rollbackFor?
  • 传播机制是否随意修改?
  • 数据库表引擎是否为 InnoDB?
  • 多数据源是否指定事务管理器?
  • 事务类是否被 Spring 管理?
  • 三、面试高频回答思路

    若面试被问及 “Spring 事务失效场景”,可按以下逻辑回答:

  • 先总述核心场景:优先说内部方法调用和异常被吞(最常见、无报错但数据出问题),再补充其他 5 种;
  • 解释核心失效原因:围绕 “Spring 事务基于 AOP 代理” 展开,代理对象未被触发是核心;
  • 补充排查方案:开启 debug 日志 + 自检清单,可快速定位问题。
  • 总结

    Spring 事务失效的核心根源是代理对象未被正确触发或配置不符合 Spring 事务规则,其中 “内部调用” 和 “异常被吞” 是最高频坑点。开发时只需严格遵循上述 7 条规则,90% 的事务问题可提前规避;排查时优先开启 debug 日志,结合自检清单,可快速定位问题根源。

    赞(0)
    未经允许不得转载:171主机测评 » Spring @Transactional 事务失效7大坑点,你踩过几个?
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址