事务失效的几种情况以及是为什么(详解)

一.Aop失效因为事务就是通过aop来实现的

Spring 先动态生成一个子类,继承你要拦截的那个类(比如 UserService)

  • 在这个子类里重写目标方法(比如 addUser)
  • 重写的方法里面,直接去调用你写的 @Aspect 切面里的 around 方法
  • 切面的 around 里先做前置逻辑(开启事务)
  • 再通过 proceed() 调用原来的父类方法(被拦截的那个方法)
  • 最后做后置逻辑(提交 / 回滚)

AOP 基于动态代理实现,只有调用【代理对象】的方法,才会走切面的前置 → joinPoint.proceed () → 后置流程,增强才生效。

1. 方法被 private 修饰(失效)

  • private 方法只能在当前类内部访问,代理对象通过反射 / 继承都调用不到这个方法
  • 代理进不去,切面流程走不起来,proceed() 根本触发不了
  • 最终:事务、AOP 增强直接失效
  • 也就是joint.proceed方法无法调用。(第四部无法完成)

2. 方法被 final /static 修饰(失效)

  • final 方法:不能被代理类重写,代理没法给方法套增强逻辑(也就是第二步没有办法完成)
  • static 方法:属于类,不属于对象实例,代理管不了静态方法
  • 结果:代理无法增强,proceed() 不执行,AOP 失效。

3. 类没有被 Spring 管理(没加 @Service/@Component 等)(失效)

  • 类没交给 Spring 管理,就不会被放进 IOC 的 Map 容器
  • Spring 不会为它生成代理对象
  • 连代理都没有,自然没有切面流程,proceed() 不存在
  • 结果:AOP 完全不生效
  • 也就是无法被继承(第一步无法完成)

4. 类内部自调用(this. 方法 ())(最经典失效)

  1. 外部调用 → 走代理对象,执行 AOP 前置逻辑
  2. 执行 joinPoint.proceed() → 进入原始目标对象(this)
  3. 原始对象里自调用方法,此时代理对象已经不存在了
  4. 自调用不走代理,第二次的 AOP 拦截完全失效
  5. 被调用方法的增强逻辑全部丢失

这个具体就是:

1. this 到底是谁?

  • 外部调用方法时,用的是Spring 生成的代理子类对象 ,此时 this = 代理对象
  • 执行 proceed() 调用父类(原类)的原方法后→ 原方法里的 this 直接变成了【原类对象(父类)】,不再是代理子类对象!

2. 父类(原类)根本调用不到子类(代理)的重写方法

  • 子类能重写父类方法,但父类永远看不到、调用不到子类的方法
  • 原类内部自己调用自己的方法(自调),比如 this.methodB()→ 这个 this 是原类对象,只能调用原类自己的原生 methodB→ 完全绕开了代理子类重写的、带 AOP 切面的方法

3. 最终结果

AOP 切面没被执行,事务、日志等增强逻辑直接失效

二、非aop的情况

  • 数据库引擎本身不支持事务MySQL 的 MyISAM 引擎就没有事务功能,不管你 Spring 事务怎么写、代理正不正常,都不可能回滚。只有 InnoDB 引擎才支持事务。

  • 异常被自己 try-catch 吃掉了,没抛出去 Spring 事务是靠捕获异常来触发回滚的。你在事务方法里把异常 catch 住,又不往外抛,Spring 根本不知道出错了,就不会回滚。

  • 抛出的异常不是 Spring 默认回滚的类型 Spring 事务默认只回滚 RuntimeException(运行时异常)和 Error 。像 IOException、SQLException 这种编译期受检异常 ,默认不会触发回滚,必须手动加:@Transactional(rollbackFor = Exception.class)

  • 事务传播行为配置错了比如把传播级别写成:

    • NOT_SUPPORTED:不支持事务,已存在的事务也挂起
    • NEVER:绝不允许有事务,有就抛异常事务根本不会开启,自然失效。
  • 多线程里调用事务方法 Spring 事务是和当前线程绑定的。新开线程去调用事务方法,新线程拿不到原来的事务,也走不到事务上下文,事务直接失效。

  • 没有开启事务注解驱动 老式 Spring 项目需要手动加 @EnableTransactionManagement 才能让 @Transactional 生效,没加的话注解等于白写。

相关推荐
夏幻灵6 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码6 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
bkspiderx8 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
代码什么用8 小时前
Spring基础使用
java·后端·spring
程序员老陆8 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光8 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
Su米苏8 小时前
Spring AI 中MCP 与普通 @Tool的区别
java·人工智能·spring
码云数智-园园8 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言
老板一杯拿铁9 小时前
Java 异常体系详解:从字节码原理到最佳实践
java
蜗牛互联网9 小时前
Java 17 HttpClient调用文件转写API的超时与失败回退
java·人工智能·后端