博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring-奇怪的回滚
阅读量:5844 次
发布时间:2019-06-18

本文共 1591 字,大约阅读时间需要 5 分钟。

上周我遇到了一个奇怪的问题,异常被try住的情况下,事务仍然回滚了。

public class ServiceA{    public void methodA(){        ...; // 执行插入        try{            serviceB.methodB(); // 这一行抛了异常        } catch (Exception e){}    }}public class ServiceB{   public void methodB(){      ...;// 执行插入   } }复制代码

ServiceA与ServiceB都由Spring来管理事务,ServiceB在ServiceA的方法中被调用,而且ServiceB周围有个try块。

一般来讲,顺着去理解,既然异常被try住了,那么就不会引起事务回滚。但抛异常的时候还是义无反顾的回滚。

拔屌无情。

ServiceB周围如果没有那个try块,回滚就很好理解了。所以为什么呢?

只能回头去查配置。两个类、事务、嵌套…… ……唔,多半和这个有关

复制代码

propagation,此参名为事务传播方式,除“REQUIRED”外,还存在“REQUIRES_NEW”等,共7种传播方式。其它的不提,因为本次问题只与这两种方式有关。

“REQUIRED”:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。

“REQUIRES_NEW”:新建事务,如果当前存在事务,把当前事务挂起。

那末,就是因为配置了“REQUIRED”的关系,导致ServiceA与ServiceB共享一个事务,一起提交,一起回滚,所以当ServiceB抛异常时,即便被try住,还是带着ServiceA一起回滚了。当我把配置改成“REQUIRES_NEW”,ServiceB与ServiceA就各玩各的。ServiceB的异常被try住后,ServiceA的操作还是可以继续执行,提交事务。

ok,问题解决了。

可,为什么呢?

Spring是怎么管理事务的?

 AOP

那这个东西说的简单点,就是Spring会为每一个它管理的类,都生成一个代理类,并且对外只提供代理类,操作也都靠代理类来完成。

这是原来的

public class ServiceB{   public void methodB(){      ...;// 执行插入   } }复制代码

代理完后基本上变成这样

public class ServiceBProxy{    private ServiceB serviceB;        public void methodBProxy(){        try{            beginTransaction();            serviceB.methodB();            commit();        }catch(Exception e){            rollback();        }    }}复制代码

那么整个流程的伪码,最后是不是就长这样(当然我这个伪码还是很伪的,而且有一部分猜测在里面)

所以当事务传播方式为“REQUIRED”时,serviceA内写try块也没用,serviceB产生的异常,已经先一步被serviceB代理类的try块捕获,导致事务回滚。

其实到这一步,再动动脑子就发现了,改一下try块的粒度,就可以做到在“REQUIRED”条件下,即便抛异常也提交事务。

在serviceB方法内部加try块的话,异常直接捕获,不会逃离到serviceB代理类的try块里,代码继续执行,因此事务也不会提交。

但走这种邪门歪路还是有风险的,老老实实新开一个事务比较好。

转载地址:http://cshcx.baihongyu.com/

你可能感兴趣的文章
目标与绩效管理实战专家胡立
查看>>
axios 中断请求
查看>>
2014手机分析图
查看>>
Linux PID 1 和 Systemd
查看>>
一元多项式相加
查看>>
commandLink/commandButton/ajax backing bean action/listener method not invoked (转)
查看>>
软件工作的大环境
查看>>
梅沙教育APP简单分析-版本:iOS v1.2.21-Nathaneko-佳钦
查看>>
Word中如何设置图片与段落的间距为半行
查看>>
JQuery this和$(this)的区别及获取$(this)子元素对象的方法
查看>>
关于分区索引与全局索引性能比较的示例
查看>>
C语言之指针与数组总结
查看>>
沟通:用故事产生共鸣
查看>>
1080*1920 下看网站很爽
查看>>
Android类参考---Fragment(一)
查看>>
CMake 构建项目Android NDK项目基础知识
查看>>
算法 - 最好、最坏、平均复杂度
查看>>
MySQL 不落地迁移、导入 PostgreSQL - 推荐 rds_dbsync
查看>>
[Erlang 0004] Centos 源代码编译 安装 Erlang
查看>>
51 Nod 1027 大数乘法【Java大数乱搞】
查看>>