Spring事务及原理,Spring事务失效的八大场景与原因分析

一、事务管理

1 编程式事务管理。

1.1 取消事务的自动提交 conn.setAutoCommit(false)。

1.2 执行业务操作。

1.3 catch块 发生异常时,回滚 conn.rollback()。

1.4 finally块 必执行,提交 conn.commit()、conn.setAutoCommit()。

2 声明式事务管理

@Transcational 对原有的业务逻辑实现增强事务操作

原理:

1.默认使用JDK动态代理、若没有出现接口或者@EnableTranscationManagement(proxyTargetClass=true)属性则转而使用CGLIB动态代理。

2.基于AOP完成对业务逻辑的事务操作 TrancationAspectSupport事务管理切面 invokeWithinTransaction()异常通知、返回通知执行目标方法 。

三、Spring事务失效的八大场景与原因分析

1.数据库不支持事务 事务型存储InnoDB

2.方法是private的:Spring事务是会基于CGLIB来进行AOP的,而CGLIB会基于父子类来失效,子类是代理类,父类是被代理类,如果父类中的某个方法是private的,那么子类就没有办法重写他,也就没有办法额外增加Spring事务的逻辑。

3.方法是final的:原因和private一样的,也是由于子类不能重写finally中的方法。

4.异常被吃掉:如果Spring事务没有捕获到异常,那么也就不用回滚了,默认情况下Spring会捕获RuntimeException和Error。

5.类没有被Spring管理。

6.单独的线程调用方法:当Mybatis或JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,如果开启事务的线程和执行SQL的线程是同一个,那么就能拿到数据库连接对象, 如果不是同一个线程,那就拿到不到数据库连接对象,这样,Mybatis或JdbcTemplate就会自己去新建一个数据库连接用来执行SQL,此数据库连接的autocommit为true,那么执行完SQL就会提交,后续再抛异常也就不能再回滚之前已经提交了的SQL了。

7.没加@Configuration注解:如果用SpringBoot基本没有这个问题,但是如果用的Spring,那么可能会有这个问题, 这个问题的原因其实也是由于Mybatis或JdbcTemplate会从ThreadLocal中去获取数据库连接,但是ThreadLocal中存储的是一个ThreadLocalMap,ThreadLocalMap的key为DataSource对象,value为连接对象,而如果我们没有在ApplicationConfig上添加@Configuration注解的话,会导致MAP中存的DataSource对象和Mybatis和JdbcTemplate中的DataSource对象不相等,从而也拿不到数据库连接,导致自己去创建数据库连接了。

8.方法内的自调用: Spring事务是基于AOP的,只要使用代理对象调用某个方法时,Spring事务才能生效, 而在一个方法中调用使用this.xxx()调用方法时,this并不是代理对象,所以会导致事务失效。 a.解放办法1:把调用方法拆分到另外一个Bean中 b.解决办法2:自己注入自己 c.解决办法3:AopContext.currentProxy()+@EnableAspectJAutoProxy(exposeProxy = true)

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值