一.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. 方法 ())(最经典失效)
- 外部调用 → 走代理对象,执行 AOP 前置逻辑
- 执行
joinPoint.proceed()→ 进入原始目标对象(this) - 原始对象里自调用方法,此时代理对象已经不存在了
- 自调用不走代理,第二次的 AOP 拦截完全失效
- 被调用方法的增强逻辑全部丢失
这个具体就是:
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生效,没加的话注解等于白写。