找回密码
 立即注册
首页 业界区 安全 @Transactional 什么情况下会失效

@Transactional 什么情况下会失效

佴莘莘 2025-6-10 20:39:04
@Transactional 注解在 Spring 中用于声明式事务管理,但在某些场景下会失效。
1、方法非 public 修饰


  • 原因:Spring AOP 代理(CGLIB/JDK 动态代理)无法拦截 private/protected 的方法。
  • 解决:确保事务方法为 public。
  1. // ✅ 正确
  2. @Transactional
  3. public void createUser() { ... }
  4. // ❌ 失效
  5. @Transactional
  6. private void createUser() { ... }
复制代码
2、自调用问题(同类内调用)


  • 原因:类内部方法调用(如 A.a() 调用 A.b())会绕过代理对象,导致 @Transactional 失效。
  • 解决:
        ① 注入自身代理对象:@Autowired private MyService self; 后调用 self.b()
        ② 通过 AopContext 获取代理:((MyService) AopContext.currentProxy()).b()(需开启 @EnableAspectJAutoProxy(exposeProxy = true))。我更喜欢把逻辑写到另一个类中,然后再进行调用。
  1. @Service
  2. public class UserService {
  3.     @Autowired
  4.     private UserService self; // 注入自身代理
  5.     public void methodA() {
  6.         // ❌ 直接调用失效
  7.         // methodB();
  8.         // ✅ 通过代理调用生效
  9.         self.methodB();
  10.     }
  11.     @Transactional
  12.     public void methodB() { ... }
  13. }
复制代码
3、异常类型未被捕获


  • 原因:
         默认只捕获 RuntimeException 和 Error
         若抛出 IOException 受检异常,事务不会回滚。
         若异常被 catch 后未重新抛出,事务失效。

  • 解决:
        ① 使用 rollbackFor 指定异常类型:@Transactional(rollbackFor = Exception.class)
        ② 避免在方法内吞没异常。
  1. // ✅ 回滚受检异常
  2. @Transactional(rollbackFor = Exception.class)
  3. public void update() throws IOException {
  4.     try {
  5.         // 数据库操作
  6.     } catch (Exception e) {
  7.         // ❌ 错误:吞没异常
  8.         // log.error(e);
  9.         // ✅ 正确:重新抛出
  10.         throw new BusinessException(e);
  11.     }
  12. }
复制代码
4、数据库引擎不支持事务


  • 原因:如 MySQL 的 MyISAM 引擎不支持事务(仅 InnoDB 支持)。
  • 解决:确认使用支持事务的引擎(比如 InnoDB 引擎)。
5、事务传播行为配置不当


  • 原因:若内层方法使用 Propagation.NOT_SUPPORTED 或 Propagation.NEVER 等传播行为,会挂起外层事务。
  • 解决:根据业务需求调整传播行为(如 Propagation.REQUIRED)。
  1. // ❌ 内层方法挂起事务
  2. @Transactional(propagation = Propagation.NEVER)
  3. public void innerMethod() { ... }
复制代码
6、多线程调用(异步调用


  • 原因:新线程内执行数据库操作不归属同一事务(事务绑定到 ThreadLocal)。异步方法(如使用 @Async 注解的方法)不会参与当前事务。即使该方法被 @Transactional 注解标记,事务也不会生效。
  • 解决:避免跨线程操作,或手动传递事务上下文(比较复杂)。
7、非 Spring 管理的 Bean


  • 原因:通过 new 创建的对象不受 Spring 代理管理。
  • 解决:确保对象由 Spring 容器创建(如 @Component)。
8、方法 final 或 static


  • 原因:CGLIB 无法代理 final/static 方法(JDK 代理无法代理 static)。
  • 解决:避免修饰事务方法为 final 或 static
9、未启用事务管理


  • 原因:忘记添加 @EnableTransactionManagement(Spring Boot 中自动配置)。
  • 解决:检查配置类是否启用事务管理。
10、非事务性方法调用


  • 原因:如果在事务方法内部调用了另一个没有事务管理的方法,事务将不会传播到被调用的方法中。事务只会在当前方法的调用栈中生效。
  • 解决:确保所有需要事务的操作都在事务方法中。
这些都是 @Transactional 可能失效的常见原因。如果遇到事务失效的问题,可以逐一排查这些情况。在工作中,有时出现了数据不一致的情况,去排查才发现是事务失效了。
知是行之始,行是知之成。-- 烟沙九洲

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册