spring事务和事务的失效场景

再spring中要使用事务,很简单,只需要在要加事物的方法上加上一个@Transtional注解就行,这个注解可以加载接口或者类上,如果加载类上或者接口上,那就表示这个类上或者接口上都加了事务管理。

 spring中有事务传播机制,就是两个用来规定两个都加了事务的方法,再被调用时的规则,是新创建一个事务,还是加入调用者的事务,还是抛异常,就比如a(),b()方法上都加了@transtational注解,b()方法里调用a()方法注解,那么,a()方法里可以设置事务传播机制,选择加入b()方法的事务,还是自己重新开一个事务,还是抛异常等等。。。。

事务的传播机制有几种,但我们主要记住REQUIRE:加入调用者的事务(默认的),REQUIRES_NEW:无论调用者有没有事务都自己创建一个事务。

像这里,delete()方法,他调用了deleteByDeptId()方法,就会有用到事务传播机制,用到的默认的require

 如果要设置事务传播机制,可以在propagation中设置。

 

下面说一下事务失效的场景:

1.同一个类中的方法自调用:

因为事务的注解@transactional注解要代理对象才能检测到,比如再同一个类中b()方法调用了a()方法,b()方法是代理对象执行的,但是a()方法是普通对象执行的,所以检测不要a()方法上的@transactional注解,因为a()方法事务会失效,要解决这种问题,1.可以把a()方法写到另一个类中,然后再把这个类的对象注入进来,再用那个类代理对象调用a()方法。2.可以自己注入自己,再用自己这个类的代理对象调用a()方法。

 第2中方法:

 

第二种失效的情况:就是这个方法不是public或者有final修饰,比如a()方法是private,因为这种情况,这个方法是不会被代理对象重写的,代理对象自己就没有这个方法,他没有额外的逻辑去执行a()方法,他不会去开启事务(setAutocommit=0),不会提交事务,回滚啥的,就是直接执行a方法里的sql,执行完sql就提交了,所以事务就失效了。

第三种失效情况是:方法内,有另一个线程执行了sql:,虽然在a()方法上加了@transactional注解,但是因为方法内sql在一个新线程内,所以这个sql会再这个线程内检测有没有开启事务,有没有建立数据库连接,如果没有,他就会自己建立一个新的数据库连接,他自己的新建的数据库连接里面的autocommit=1,也就是自动提交,所以sql一执行完就会提交,不管后面抛步抛异常。

 

第四种失效的情况就是:配置类失效了没有加@Configurtion注解,这种咋spring中常见,再boot中比较少:

 再配置类里面,配置了jdbcTemplate,和platformTransactionManager,这两个bean都需要一个DataSource对象,如果我们加了@Configtration注解,那么这个appconfig就会生成代理对象,执行代理逻辑,再代理逻辑里,会给jdbcTemplate和platformTransactionManager,提供同一个数据源DataSource

这样我们在执行a()方法时,上面的@transational注解生效时,会生成一个DataSource数据源,和connection数据库连接,并且把这个DataSource作为key,connection作为值存进map里面,把map存进TrealLocal里面,还会把autocommit设置为0,也就是false关闭自动提交。所以当我们的jdbcTemplate在执行时,他会先去ThreadLocal里面找有没有他的DataSource的对应的connection,

如果我们在配置类上加了@configurtion注解,那么jdbc和transactional两个对象的DataSource应该是一样的,因此,jdbc能用DataSource在ThreadLocal里面的map里面找到transactional创建的connection,也就是transactional和jdbc用同一个connection,他的autocommit已经设置为了false,所以不会自动提交,因为事务不会失效。 

如果我们没有在配置类appconfig上家@configuration注解,那么jdbc和transactional两个的DataSource就不一样,不一样,那jdbc就不能再ThreadLocal的map李找的transactional创建的connection,所以jdbc他会自己创建一个connection,jdbc创建的connection没有设置autocommit=false,所以sql一执行完,就会提交,因此事务失效了。

第五种情况就是:方法内出现的异常不是RuntimeException或者error,因为transactional默认是只能检测到运行时异常和error才回滚,如果是编译时异常,那么就检测不到也就不会回滚:

所以有两种方法:

1.设置所以异常有检测到,都回滚:

2:把编译时异常try--catch,再catch里面,抛出一个运行时异常 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值