Spring中事务嵌套这么用一定得注意了!!
2023-04-22 11:20:56 来源:博客园
前言

最近项目上有一个使用事务相对复杂的业务场景报错了。在绝大多数情况下,都是风平浪静,没有问题。其实内在暗流涌动,在有些异常情况下就会报错,这种偶然性的问题很有可能就会在暴露到生产上造成事故,那究竟是怎么回事呢?

问题描述

我们用一个简单的例子模拟下,大家也可以看看下面这段代码输出的结果是什么。

在类SecondTransactionService定义一个简单接口transaction2,插入一个用户,同时必然会抛出错误
@Override@Transactional(rollbackFor = Exception.class)public void transaction2() {    System.out.println("do transaction2.....");    User user = new User("tx2", "111", 18);    // 插入一个用户    userService.insertUser(user);    // 跑错了    throw new RuntimeException();}
在另外一个类FirstTransactionService定义一个接口transaction1,它调用transaction2方法,同时做了try catch处理
@Override@Transactional(rollbackFor = Exception.class)public void transaction1() {    System.out.println("do transaction1 .......");    try {        // 调用另外一个事务,try catch住        secondTransactionService.transaction2();    } catch (Exception e) {        e.printStackTrace();    }    // 插入当前用户tx1    User user = new User("tx1", "111", 18);    userService.insertUser(user);}
定义一个controller,调用transaction1方法
@GetMapping("/testNestedTx")public String testNestedTx() {    firstTransactionService.transaction1();    return "success";}

大家觉得调用这个http接口,最终数据库插入的是几条数据呢?


(资料图片仅供参考)

问题结果

正确答案是数据库插入了0条数据。

同时控制台也报错了,报错原因是:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

是否和你预想的一样呢?你知道是为什么吗?

原因追溯

其实原因很简单,我们都知道,一个事务要么全成功提交事务,要么失败全部回滚。如果出现在一个事务中部分SQL要回滚,部分SQL要提交,这不就主打的一个”前后矛盾,精神分裂“吗?

controller.testNestedTx()   ||   / FirstTransactionService.transaction1()   REQUIRED隔离级别       ||        ||        || 捕获异常,提交事务,出错啦       / || FirstTransactionService.transaction2()   REQUIRED隔离级别       || ||        || 抛出异常,标记事务为rollback only       =======================
事务的隔离级别为REQUIRED,那么发现没有事务开启一个事务操作,有的话,就合并到这个事务中,所以transaction1()transaction2()是在同一个事务中。transaction2()抛出异常,那么事务会被标记为rollback only, 源码如下所示:transaction1()由于try catch 异常,正常运行,想必就要可以提交事务了,在提交事务的时候,会检查rollback标记,如果是true, 这时候就会抛出上面的异常了。源码如下图所示:

这下,是不是很清楚知道报错的原因了,那想想该怎么处理呢?

解决之道

知道了根本原因之后,是不是解决的方案就很明朗了,我们可以通过调整事务的传播方式分拆多个事务管理,或者让一个事务"前后一致",做一个诚信的好事务。

try catch放到内层事务中,也就是transaction2()方法中,这样内层事务会跟着外部事务进行提交或者回滚。
@Override    @Transactional(rollbackFor = Exception.class)    public void transaction2() {        try {            System.out.println("do transaction2.....");            User user = new User("tx2", "111", 18);            userService.insertUser2(user);            throw new RuntimeException();        } catch (Exception e) {            e.printStackTrace();        }    }
如果希望内层事务抛出异常时中断程序执行,直接在外层事务的catch代码块中抛出e,这样同一个事务就都会回滚。如果希望内层事务回滚,但不影响外层事务提交,需要将内层事务的传播方式指定为PROPAGATION_NESTEDPROPAGATION_NESTED基于数据库savepoint实现的嵌套事务,外层事务的提交和回滚能够控制嵌内层事务,而内层事务报错时,可以返回原始savepoint,外层事务可以继续提交。事务的传播机制

前面提到了事务的传播机制,我们再看都有哪几种。

PROPAGATION_REQUIRED:加入到当前事务中,如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring中默认采用的方式。PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。PROPAGATION_REQUIRES_NEW:新建一个事务,如果当前存在事务,把当前事务挂起。PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。PROPAGATION_NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

如何理解PROPAGATION_NESTED的传播机制呢,和PROPAGATION_REQUIRES_NEW又有什么区别呢?我们用一个例子说明白。

定义serviceA.methodA()PROPAGATION_REQUIRED修饰;定义serviceB.methodB()以表格中三种方式修饰;methodA中调用methodB;总结

在我的项目中之所以会报“rollback-only”异常的根本原因是代码风格不一致的原因。外层事务对错误的处理方式是返回true或false来告诉上游执行结果,而内层事务是通过抛出异常来告诉上游(这里指外层事务)执行结果,这种差异就导致了“rollback-only”异常。大家也可以去review自己项目中的代码,是不是也偷偷犯下同样的错误了。

欢迎关注个人公众号【JAVA旭阳】交流学习

“旺季”来临!煤炭板块走高 云煤能源、陕西黑猫涨停

2023-09-09

北极冰川中出现巨大冰窟窿 面积大小相当于韩国面积的70%

2023-09-09

皇马球员罗德里戈,巴尔韦德和楚阿梅尼在国际比赛日...

2023-09-09

他是村民健康“守门人”

2023-09-09

中信博:融资净买入9327元,融资余额1.24亿元(09-08)

2023-09-09

若昂保罗二世机场(关于若昂保罗二世机场简述)

2023-09-09

常州举办“专精特新”企业股改上市培训活动 积极支持北交所“扩容”

2023-09-08

借款人可否提前偿还住房公积金贷款

2023-09-08

深圳特大暴雨 :营救疏散逾600位被困人员 转移民众超1600人

2023-09-08

花样年位于成都的4宗地块将被拍卖,总起拍价约5.57亿元

2023-09-08

“中国数坝”张家口大数据产业对接会举行 8个项目签约总投资80.15亿元

2023-09-08

中油工程:签订30.33亿元施工总承包合同

2023-09-08

粉蒸羊肉的做法最正宗的做法视频教程(粉蒸羊肉的做法最正宗的做法)

2023-09-08

梅西赛后与厄瓜多尔门将交换球衣,两人儿时是邻居曾经常交手

2023-09-08

限时抢购Redmi 红米 Note11T Pro 5G 1699元

2023-09-08

广西省造老银元价格(2023年09月08日)

2023-09-08

打破信息壁垒,皮小度让专业美肤方案触手可及

2023-09-08

旷达科技(002516):MACD指标DIF线上穿0轴-技术指标上后市看多(09-08)

2023-09-08

存款利率一降再降,大行存款规模却大幅增加!钱从哪里来的?

2023-09-08

人民银行开展1010亿元逆回购操作 公开市场实现净回笼1200亿元

2023-09-01

如何做好出厂后组件的隐裂控制?

2023-09-01

圆通速递(600233)8月31日主力资金净买入731.34万元

2023-09-01

文明海南 | 七旬老人为孤残侄女筑起幸福港湾

2023-09-01

药品包装机(关于药品包装机简述)

2023-09-01

突发!一栋五层建筑失火,已致73人遇难

2023-08-31

武铁暑运火爆收官:发送旅客3808万人次,装运货物1662万吨,双双创新高

2023-08-31

税务专管员回应宋祖儿被举报上热搜,税务系统内部人士:分局专员无举报受理权限,不知情很正常

2023-08-31

ST小桥2023年上半年净利-98.14万 由盈转亏

2023-08-31

中毛自贸区联委会首次会议在路易港举行

2023-08-31

A0级小型车,几何E萤火虫、海鸥、缤果怎么选?

2023-08-31

芯途异构宣布完成千万级天使轮融资

2023-08-31

“五经普”动态丨湖南:全面构建第五次经济普查工作宣传格局

2023-08-31

造梦西游3号和密码大全真的(造梦西游3号和密码90级)

2023-08-31

格力电器:上半年实现营业收入992.37亿元

2023-08-31

长株潭获批综合型流通支点城市

2023-08-31

假面骑士Gotchard:三骑雷杰多未有追加情报放出,难道小明哥回归只是一个噱头

2023-08-31

儿童棒棒糖,来自日本核辐射地区!已立案调查

2023-08-31

南方航空上半年营收同比增长约76%,厦门航空扭亏为盈

2023-08-31

今日公告透露利好:6只个股有潜力

2023-08-31

深市分红三大新趋势彰显公司回报意识攀升 主板去年现金分红超过股权融资金额

2023-08-30

股票行情快报:方大炭素(600516)8月30日主力资金净卖出1042.68万元

2023-08-30

关羽的“智多星”,计谋不输诸葛亮,关羽若听他的话,荆州不会丢

2023-08-30

同方知网与华为云签约,共建华知大模型

2023-08-30

这国局势突变!中国使馆紧急提醒中国公民不外出

2023-08-30

习近平对四川凉山州金阳县山洪灾害作出重要指示

2023-08-30

上座率达九成,中杂《双奥密境》成为暑期旅游演出热门项目

2023-08-30

江苏金租增资获批 注册资本将增至约42.45亿元

2023-08-30

德必集团:8月29日融资买入840.21万元,融资融券余额4064.32万元

2023-08-30

债主变股东!碧桂园拟发行3.51亿股新股,建滔集团旗下企业认购

2023-08-30

太行山水 漳河画廊

2023-08-30

品牌建设引领产业振兴——哈尔滨县域经济发展一线观察

2023-08-30

第九套广播体操 mp3音乐(第九套广播体操 mp3)

2023-08-30

男篮世界杯:16强已出10席 亚洲5队已出局

2023-08-30

留一半清醒,留一半醉

2023-08-29

公职人员被举报酒后辱骂殴打村民 单位回应:公安和纪委正在调查

2023-08-29

江苏雷利:接受海南恒立私募等机构调研

2023-08-29

全新配色不简单!Nike Vaporfly 3 又有新配色!

2023-08-29

2023蜀里安逸四川消费券领取步骤(图解)

2023-08-29

8月29日国内萤石产业链部分价格上涨

2023-08-29

区位码和国标码之间的转换(区位码与国标码的转换)

2023-08-29

春秋战国时期变法(春秋战国时期)

2023-08-29

迈信林:8月28日融资买入362.18万元,融资融券余额3594.67万元

2023-08-29

中铁工业上半年实现净利润10亿元 同比增长8.04%

2023-08-29

美国人普遍认为拜登年龄太大,不宜连任美国总统

2023-08-29

康普顿上半年净利3711万 同比增21%;小鹏58亿收购滴滴汽车业务丨AC早报

2023-08-29

每体:费尔明将与巴萨续约至2028年,解约金4亿欧

2023-08-29

仁和药业董事长杨潇合计增持183万股公司股份 耗资1204.14万元

2023-08-28

云天化:上半年实现净利润26.78亿元

2023-08-28

[c/洛/猫/红/卡]照进末地的光.4

2023-08-28

真我GT5销量公布:打破今年所有手机新品尝鲜购销量纪录

2023-08-28

dnf自动刷图脚本哪个比较好_dnf自动刷图脚本

2023-08-28

东方米兰国际城户型图(东方米兰国际城)

2023-08-28

satellite tool kit下载

2023-08-28

永胜医疗(01612)将于9月29日派中期股息每股0.0125港元

2023-08-28

高居中乙榜首,重庆铜梁龙主帅:足协杯踢申花,我们抱着学习态度

2023-08-28

龙佰集团8月28日开盘涨幅达5%

2023-08-28

安徽决定:在全省范围内排查

2023-08-28

周一机构一致最看好的10金股

2023-08-28

受洗的意义和目的讲章(受洗)

2023-08-28

蔚来能源与雅诗阁签订绿色能源合作协议

2023-08-27

同屏器干啥用的_同屏器是什么

2023-08-27

不够的组词(不够组词)

2023-08-27

水蒸荷包蛋怎么蒸最好吃

2023-08-27

国家统计局:1-7月全国规上工业企业利润下降15.5%

2023-08-27

送孩子上学的经典语句

2023-08-27

关于悟道

2023-08-27

【小里帮忙】煜城阳光花邸小区30号楼频繁停水,物业:一加压就爆管

2023-08-27

安徽幼师高等专科学校排名 安徽幼师学校有哪些

2023-08-27

惨败塞尔维亚!事实证明,赵继伟、王哲林、李凯尔打不了国际大赛

2023-08-26

什么情况构成敲诈勒索行为

2023-08-26

桂林记录者:苗医廖德银,传承千年苗医 弘扬仁心医术

2023-08-26

成都车展直击:电动车狂奔,燃油车末路?

2023-08-26

四川省威远县发布大风蓝色预警

2023-08-26

违规开展学科类校外培训,武汉这些机构(个人)被查处!

2023-08-26

恐怖游戏《逃生:试炼》推迟至明年登陆 PS5、Xbox 主机平台

2023-08-26

副院长微信号被盗 晒“副处长礼物”博主发文:被盗号 基本情况讲解

2023-08-26

西安——亿科江山悦丨楼盘测评

2023-08-26

竞业达(003005):8月25日北向资金增持35.58万股

2023-08-26

肚包鸡的做法大全窍门(肚包鸡的做法)

2023-08-25

中国再次逮捕了一名美国间谍。法媒报道称,在华的11万名间谍

2023-08-25