小心 MybatisPlus 的一个坑与面试题

news2024/11/25 0:44:38

昨天测试说有个 xx 功能用不了,扔给我一个截图,说有报错:

报错信息就是:Transaction rolled back because it has been marked as rollback-only,很好理解:事务被回滚了,因为它已经被标记了只能回滚。

我一看巧了,这不就是我之前分析过的面试题吗!

之前的文章我解释过:这种错一般发生在嵌套事务中,即内层事务出错,但是由于是否提交事务的操作由外层事务触发,于是乎内层事务只能做个标记,来设置当前事务只能回滚。

紧接着它想抛出错误,但是由于被 try catch 了,于是乎正常执行后续的逻辑,等执行到最后,外层要提交事务了,发现当前事务已经被打了回滚的标记,所以提交失败,报了上面的错。

具体原理可以看我之前的那篇文章,这里简单举例下会出错的示例代码:

大致就是下面这个代码调用逻辑,有一个 service 标记了 @Transcational,采用默认的事务传播机制:

紧接着 UserService#insert 调用了 addressService#errorInvoker,这个方法也标记了 @Transcational:

这样一来,只要 addressService#errorInvoker 的调用发生报错,那么必然能重现上面的报错信息。

原理很清晰,我不可能犯这个错。

我信誓旦旦的对测试说:这肯定是老陈写的 bug,与我无关!

老陈瞄了我一眼:老子已经 2 个月没碰过那个项目了,你扯犊子呢?

随后这个老测试直接把更详细的报错扔了过来,咳咳,涉及公司的类名这里不展示的,反正确实是我的代码....

但是我还是觉得很不可思议,这部分逻辑是我新写的,我压根就没有使用嵌套事务啊!

大致的代码如下:

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean xxx(xxx dto) {
        list1 = .....;
        try {
              数据库批量保存list1;
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                //筛选过滤重复 key 的数据
                //打标发送
                数据库批量保存过滤之后的list1;
            }
            ....
        }
        sendToMQ(xxx);
        list2 = .....;
        try {
             数据库批量保存list2;
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) {
                //筛选过滤重复 key 的数据
                //打标发送
                数据库批量保存过滤之后的list2;
            }
            ...
        }
        sendToMQ(xxx);
        return Boolean.TRUE;
    }

这个接口其实是一次性接口,用来补数据的,线上跑过一次后,后面应该不会再使用。

出于保险原则,兼容上游部分数据重复调用,所以我做了重复key的处理,剔除重复的部分,让不重复的部分正常保存。

正常情况下不会出现这个场景,刚好测试环境测试来回折腾有很多重复数据(其实我这样写也是为了兼容测试,随便他折腾)

这里的代码逻辑不复杂,明面上来看,我并没有调用别的 service !也并不存在嵌套事务的问题,所以我思来想去也看不明白。

于是......

我出门放了个水,顺带逛了一圈,接着买了杯咖啡,遇事不决,量子力...个屁,立马屁颠屁颠的跑回来继续看代码。

回来突然就看 try-catch 不爽。

但是 try 里面就是一个  mybatis-plus 的 IService,批量保存数据的操作。

难道它有什么骚操作?点进去一看突然发现:

我丢!

唤起了我的记忆,mybatis-plus 为了保证批量保存的事务性,加了 @Transactional

合着我确实没想着使用嵌套事务,但是这被迫上了“贼船”啊!

这本是好意,但是在我这个场景有点麻,它完美的复现了上文提到的那个错误使用,在有重复 key 的场景确实报错了,但是被外层 try-catch 拦住了抛错,不过事务上已经打了失败的标了!

解决办法其实很简单:

  1. 把 saveBatch 上的 @Transactional 注解删了,很明显我做不到,这是 mybatisplus 的源码。

  2. 把 saveBatch 上的 @Transactional 注解上设置事务传播机制为:REQUIRES_NEW 或 NESTED,很明显,我也做不到,这是 mybatis-plus 的源码。

然后我找了下,好像也没有什么参数可以指定 saveBatch 的事务传播机制。

所以咋办。。。测试还在催我,没办法,只能不用 mybatis-plus 的 saveBatch ,自己通过 mapper 写个批量插入了:

一波操作提交代码重启服务,让测试再试试,且轻飘飘的甩一句:这不是我的bug,我被框架坑了。

咳咳,反正我不管,我的代码没有bug,这是程序员最后的倔强。

最后

所以在使用三方代码的情况下还是需要多留个心眼点点看。

我记得以前还听说过一个段子,就是有个人用了一个网上的组件,正常情况下都没事,异常情况下,系统就挂了。

后面一找,那个组件在个角落嘎达写了 System.exit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HttpRunner自动化之请求中带有 headers 的接口和发送POST请求

headers 可通过headers 添加头部信息,如下图 # 发送请求头headers的接口 - config:name: 百度接口用例base_url: https://www.baidu.com- test:name: 发送百度接口的头部信息request:url: /smethod: GETheaders:Accept: text/html,application/xhtmlxml,applicati…

LNMT(linux下nignx+mysql+tomcat(中间件)应用)部署应用、及各服务介绍、部署开源站点jpress

目录 一、环境准备 二、tomcat1和tomcat2服务器,安装配置tomcat 1.tomcat服务器介绍 2.JDK软件介绍 3.查看JDK是否安装 4.tomcat1和tomcat2服务器,安装JDK1.8.0_191(JDK必须和nginx版本相适应,不然一直报错) 5.安…

【LeetCode】HOT 100(21)

题单介绍: 精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

源启数据资产管理平台助力金融机构加速数据资产化过程

自2000年左右,金融行业开始做数据管理。从数据仓库到数据治理、数据应用,再到后来的大数据,以及今天的数据管理。我们把这个时期总结成数据资产化时代,或者叫国产化时代。 为什么有两个名字?数据资产化时代是因为国家…

关于PID闭环控制中上位机与下位机通讯代码的解析分享(一)

下位机接收数据代码(以STM32单片机为例)与上位机发送数据C#代码分享 1、下位机代码: /*** brief 接收的数据处理* param void* return -1:没有找到一个正确的命令.*/ int8_t receiving_process(void) {uint8_t frame_data[…

虚幻引擎程序化资源生成框架PCG 之 常用撒点方法小结

PCG真好玩,门槛很低,天花板很高 文章目录 前言1. 基本撒点1.1 Landscape上撒点1.2 使用射线检测在地表面撒点1.3 使用曲线撒点1.3.1 沿曲线撒点1.3.2 在闭合曲线内部撒点 1.4 在StaticMesh表面撒点 2. 进阶撒点2.1 在闭合曲线内部放射状撒点2.2 在Mesh表…

MedCalc v22.009 医学ROC曲线统计分析软详细图文教程

简介 MedCalc是一款医学 ROC 曲线统计软件,用于ROC曲线分析的参考软件,医学工作者设计的医学计算器,功能齐全。它可以帮助医生快速作出普通的医学计算,从而对症下药。提供超过76种常用的规则和方法,包括:病…

《消失的她》豆瓣短评数据分析

《消失的她》豆瓣短评数据分析 文章目录 《消失的她》豆瓣短评数据分析一、前言二、数据加载和预处理三、探索性数据分析1、查看评论的评价分布2、查看评论点赞数的分布3、查看评论的地理分布 四、情感分析 一、前言 最近爆火的电影《消失的她》你们有没有去看过呢&#xff1f…

开源站点(jpress)部署

第三阶段基础 时 间:2023年7月5日 参加人:全班人员 内 容: 开源站点部署(jpress) 服务器设置;单台服务器,安装tomcat和mariadb 环境配置: 1、关闭防火墙 systemctl stop fir…

【大数据之Hive】二十、Hive之调优相关配置及Explain查看执行计划

1 Yarn资源配置 需要调整Yarn的参数与CPU、内存等资源有关 (1)yarn.nodemanager.resource.memory-mb   设置一个NodeManager节点分配给容器Container使用的内存,取决于NodeManager所在节点的总内存容量和该节点运行的其他服务的数量&#x…

搭建高性能数据库集群之二:MySQL读写分离(基于mycat2-1.22)

一、概述 读写分离是常见的一种数据库架构,一般是由 1 主多从构成,特殊场景下也会存在多主多从的架构。 无论哪一种架构,对于应用程序来说都是多个数据源,增加了代码的复杂性。如果配合 mycat,则可以实现屏蔽数据库复…

【C++】深入剖析vector

好久不见~让大家久等啦~ 本期让我们来揭开vector的面纱,看看它底层是怎么实现的~ 目录 一、STL定义vector的源码分析: 二、vector的模拟实现 2.1 vector框架的搭建(一些简单功能函数的实现) 2.2 迭代器失效问题 2.2.1 实现i…

【Spring】SpringCloud Ribbon中的7种负载均衡策略!

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务…

个人总结:测试用例万能公式+常见例子(公式的运用)

前言 测试工程师面试的时候,有时候会当场考测试用例,毕竟这是测试工程师的基本功。 对于我来说,让我写测试用例会比让我直接说测试用例更好点。 直接嘴里说出来,容易逻辑混乱,给人一种想到啥说啥的感觉。 其实个人感…

MySQL学习基础篇(九)---子查询

MySQL学习基础篇(九)—子查询 子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入。SQL 中子查询的使用大大增强了 SELECT查询的能力,因为很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出…

MySQL安装与部署

第一种方法:在线安装 配置一个安装yum源 Adding the MySQL Yum Repository 可以手动配置yum源,baseurl指向国内镜像源地址,比如清华、中科大。 Installing MySQL Starting the MySQL Server: 查询临时登录密码 修改数据库密码…

CTFHub XSS DOM反射 WriteUp

前言:本文需要注册一个xss平台,以接收xss反弹回来的数据,请自己在互联网上寻找合适的xss平台 1. 构造闭合语句 根据题目提示,判断网站存在DOM xss漏洞 查看页面源代码,发现关键位置,其中CTFHub is very n…

【揭秘Vue核心】深入解析Object.defineProperty和Proxy的区别,让你秒懂!

问题:Object.difineProperty 和 proxy 有什么区别? Object.defineProperty 和 Proxy 是用于实现响应式数据的两种不同方式。 Object.defineProperty Object.defineProperty 通过直接修改对象的属性描述符来实现数据的劫持。Vue 2.x 中就是通过 Objec…

vscode 之 工作区的应用(解决vue2插件vetur、vue3插件volar禁用启用问题)

目录 前言创建工作区添加文件夹到工作区为当前打开的工作区指定特定环境工作区删除文件夹如何切换工作区 前言 工作区???为什么要工作区??? 首先工作区简单理解就是vscode工作时的区域、范围; 延…

如何正确的安装MySQL

1. 使用rpm包在线安装 1.1 确认自己电脑版本(linux) [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)ps:本次安装采用的系统为Centos 7.9 所使用的mysql为5.7 1.2 下载rpm包 下载地址 https://dev.mysql.com/downloads/mysql/ ps: 自己…