盘点一下@Transactional失效的场景

一、代理不生效

Spring中对注解的解析都是基于代理的,如果目标方法无法被Spring代理到,那么他就无法被Spring进行事务管理。

Spring生成代理的方式有两种:

1.基于接口的JDK动态代理,但是要求目标代理类必须要实现一个接口才能被代理

2.基于目标类子类的CGLIB代理

在Spring-boot2.0之前,如果目标类实现了接口,那么将会使用JDK动态代理,否则使用CGLIB子类的方式生成代理;

在Spring-boot2.0之后,除非在配置文件中指定spring.aop.proxy-target-class的值,否则默认情况下将会使用CGLIB生成代理。

@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop",name = "proxy-target-class",havingValue = "true",matchIfMissing = true)
public class Test(){
}

而下列原因会因为代理不生效导致事务管控失败

(1)将@Transactional注解标注在接口上

@Transactional是支持在方法与类上的,因为一旦接口实现类的代理方式是CGLIB,他会通过生成子类的方式对目标类进行代理,就会导致标在接口上的@Transactional注解无法被解析到,从而导致事务失效。

(2)被final、static关键字修饰的类或方法

CGLIB是通过生成目标类的子类的方式进行代理的,而被final、static修饰的类或方法无法被继承。

(3)类方法的内部调用

事务的管理是通过代理执行的方式生效的,如果是方法内部的调用,将不会走代理逻辑,也就无法调用到@Transacational注解了。

解决方法有三个:

        1.新建Service将方法迁移过去(不建议)

        2.在当前类中注入自己,通过注入的service调用本类方法

        3.通过AopContext.currentProxy()获取代理对象直接调用方法

(4)当前类没有被Spring管理

二、框架或底层不支持的功能

这类的失效场景主要聚焦在框架本身在解析@Transactional时的内部支持,如果使用的场景本身就是框架不支持的,那么事务也是无法生效的。

(1)非public修饰的方法

@Transactional底层不支持非public修饰的方法的事务管理。

(2)多线程调用

TransactionInfo事务信息是和线程绑定的,即当前线程中无法调用其他线程中的事务信息;

两个线程在不同的Spring事务中,本质上会导致他们在Mysql中存在不同的事务中。

(3)数据库本身不支持事务

比如MySql中的Myisam存储引擎是不支持事务的,只有innodb才支持,但是这个问题出现的概率较小,因为在Mysql5之后默认已经是innodb存储引擎了。

(4)未开启事务

这个问题只会在MVC项目中存在,因为Springboot项目已经默认开启了事务管理,

而如果想要是MVC启用事务,需要在applicationContext.xml文件中,手动配值相关参数。

三、错误使用@Transactional

(1)错误的传播机制

不支持事务的传播机制有:

        PROPAGATION_SUPPORTS,

        PROPAGATION_NOT_SUPPORTED,

        PROPAGATION_NEVER

(2)rollbackFor回滚异常设置错误

默认状态下为RunTimeException,即只会回滚运行时异常;

我们可以指定rollbackFor = Exception.class进行全异常捕获。

(3)异常被内部try catch
@Transactional(rollbackFor = Exception.class)
public void test(){
    try{
        sout(1/0);
    }catch(Exception e ){
    }
    

因为方法内虽然报错了,但是手动进行了try catch,catch中并没有进行对应的异常抛出,就会导致事务不会回滚。

(4)嵌套事务

通常当一个方法回滚时,我们希望让调用方法和数据库操作方法同时回滚,但是有时也只希望回滚数据库操作方法而不影响主方法的运行:

        方法1:直接在数据库操作方法内用try catch包住整个方法

        方法2:在数据库操作方法中使用Propagation.REQUIRES_NEW传播机制

四、总结

全文END ʕ•ᴥ•ʔ

  • 31
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值