Spring事务

事务未生效

1. 数据库存储引擎是否支持事务(例如,mysql的innodb支持事务,而myisam不支持事务)
    Spring事务是否开启(以下为注解方式开启事务)

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

2. 异常类型不是unchecked类型
    Spring默认对unchecked异常类型才会回滚,如果需要对checked类型回滚需要特别指定rollBackFor

3. 事务方法非public类型( 应该是跟代理有关,后续写文章分析)

4. 事务类被重复扫描。(例如既被Spring容器扫描,又被SpringMVC容器扫描)

事务的传播

场景一:事务方法调用非事务方法(不管是同一个Service类中的方法调用还是多个Service方法间的调用),只要抛了异常(不论是在事务方法还是在非事务方法中抛),事务都会回滚(不论是在事务方法中对DB的操作还是在非事务方法中的操作),个人理解这种场景即,最外层方法加了事务,整个方法调用链上的方法都在一个事务中。

场景二:
非事务方法调事务方法
1. 外层非事务方法内抛异常,不管是同一个Service类中的方法调用还是多个Service方法间的调用,事务与外层非事务方法都不会回滚。
2. 内层事务方法内抛异常:a. 不同Service 类方法调用,事务方法回滚,外层非事务方法不回滚。b. 同一个Service类方法调用,事务和非事务方法都不回滚。(以下场景是不会回滚的)

在一个Service内部,事务方法之间的嵌套调用,普通方法和事务方法之间的嵌套调用,不论事务传播类型是什么,都不会开启的事务。特别的,统一ServiceA下的非事务方法a调用事务方法b,整个ServiceA.a()相当于没有事务,b方法抛异常b也不会回滚。原因在于Spring事务是基于动态代理实现的,动态代理最终都需要调用原始对象,同一个类中,test2调用test3()是通过原始对象去调用的,当然不会出发事务了。如果将test3抽出在另一个Service类中并开启事务,就可以触发事务了。

参考:
https://blog.51cto.com/zhangfengzhe/2059602
https://www.cnblogs.com/yougewe/p/7466677.html 看评论就可以了

关于事务传播机制,又有了不一样的认识。2019-5-18
case1:ServiceA的事务方法a调ServiceB事务方法b,两方法事务传播规则均为required。
b方法抛异常,a方法catch住并吃掉异常,问,b方法会不会回滚?(ps:项目中看到这样的代码,同事当作会回滚逻辑coding,因为b方法上rollbackFor = Exception.class),我当时也愣住,好像有道理。但是...我细想
a调用b,事务传播规则required,则a,b在同一事务中(a开启的事务中),事务的回滚与提交在a方法上啊,a把异常吃掉了,那对a来讲就无异常咯,那当然不会回滚了。如下图

但是,经测试,抛出了org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only。
也就是,我们都错了,原因:
method_b()抛出异常时,已经将事务标记为rollback only(就是说该事务最终是要被回滚的!),因为method_b与method_a共享一事务,实际就是将method_a开始的事务标记为rollback only,但是异常被吃掉,执行到method_a末尾,提交事务,就抛异常了。(怀疑同事代码实际执行是抛出了UnexpectedRollbackException,只是被上层又catch了且上层又吃掉了且未log,所以我也搜不到日志,找不到证据)。
但是,同样的情况,method_a与method_b在同一Service类中时,情况却大有不同。

method_a与method_b正常执行,事务正常提交。因为
两方法在同一类中,method_b的事务只是摆设,其实无用,走的是this.method_b(this是ServiceA的实例),此时不会被Spring事务AOP拦截,虽然抛出了异常,但是并不会将当前事务标记为rollback only,异常被吃掉,事务正常提交。(而方法a,b不在同一类时,b方法会被Spring事务的AOP拦截到,将当前事务标记为rollback only,这是关键知识点)
所有的认知都仅仅是冰山一角,有点绝望呢。

事务的传播机制可参考:https://blog.csdn.net/trigl/article/details/50968079#commentBox 事务传播行为部分

事务传播机制,REQUIRES_NEW和PNESTED区别:https://blog.csdn.net/paincupid/article/details/48185597
虽然数据库默认的事务隔离级别是不变的,但是可以设置每次会话的事务隔离级别,可通过@Transactional的isolation属性设置每次会话的隔离级别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值