·设为首页收藏本站📧邮箱修改🎁免费下载专区💎积分✅卡密📒收藏夹👽聊天室
DZ插件网 门户 网站安全 查看内容

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...

2023-8-4 01:18| 发布者: 浅生| 查看: 82911| 评论: 0

摘要: 了解如何避免MyBatis-Plus中的@Transactional注解导致的事务回滚错误,并学习解决方法以保证代码的稳定运行。详细分析和示例代码帮助您理解问题的根源。如果您在开发过程中遇到类似问题,请参考本文内容进行修复。

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...7843 作者: 来源: 发布时间:2023-8-4 01:18

mall学习教程官网:macrozheng.com

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...5563 作者: 来源: 发布时间:2023-8-4 01:18

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...1061 作者: 来源: 发布时间:2023-8-4 01:18

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

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

推荐一套基于 SpringBoot + Vue + uni-app 实现的全套电商系统mall(Github标星60K),前台商城项目和后台管理系统都有了,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员等功能,功能很强大!
  • 项目地址:https://github.com/macrozheng/mall
  • 视频教程:https://www.macrozheng.com/video/

问题重现


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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...5960 作者: 来源: 发布时间:2023-8-4 01:18

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...4541 作者: 来源: 发布时间:2023-8-4 01:18

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

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...9846 作者: 来源: 发布时间:2023-8-4 01:18

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...7103 作者: 来源: 发布时间:2023-8-4 01:18

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

大致的代码如下:
@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 !也并不存在嵌套事务的问题,所以我思来想去也看不明白。

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...8865 作者: 来源: 发布时间:2023-8-4 01:18

于是......

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

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

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...4547 作者: 来源: 发布时间:2023-8-4 01:18

我丢!

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

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

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

解决方案


解决办法其实很简单:
  1. 把 saveBatch 上的 @Transactional 注解删了,很明显我做不到,这是 mybatisplus 的源码。
  2. 把 saveBatch 上的 @Transactional 注解上设置事务传播机制为:REQUIRES_NEW 或 NESTED,很明显,我也做不到,这是 mybatis-plus 的源码。

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...3152 作者: 来源: 发布时间:2023-8-4 01:18

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...4505 作者: 来源: 发布时间:2023-8-4 01:18

最后


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

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

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

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...5026 作者: 来源: 发布时间:2023-8-4 01:18


Github上标星60K的电商实战项目,出 视频教程(2023最新版) 了!全套教程基于SpringBoot 2.7版本,可以说内容非常新!全套教程约40小时,共100期,通过这套教程你可以拥有一个涵盖主流Java技术栈的完整项目经验,同时提高自己独立开发一个项目的能力,下面是项目的整体架构图,感兴趣的小伙伴可以点击链接 mall视频教程 加入学习。

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...6373 作者: 来源: 发布时间:2023-8-4 01:18

整套 视频教程 的内容还是非常完善的,涵盖了mall项目最佳学习路线、整体框架搭建、业务与技术实现全方位解析、线上Docker环境部署等内容,具体大纲可以参考下图,你也可以点击链接 mall视频教程 了解更多内容。

告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...1098 作者: 来源: 发布时间:2023-8-4 01:18

推荐阅读

  • Github标星60K!这套涵盖Java主流技术和电商核心业务的实战教程,太香了!
  • Github标星60K!mall前台商城系统正式发布,支持完整订单流程!
  • 订单系统就该这么设计(万能通用),稳的一批!
  • 电商系统中的商品功能就该这么设计,稳的一批!
  • 权限系统就该这么设计(万能通用),稳的一批!
  • 新入职一家公司,接手了个从零开始的项目,好难!


告警:MyBatis-Plus中慎用@Transactional注解,坑的差点被开了...4929 作者: 来源: 发布时间:2023-8-4 01:18


上一篇:提速中小企业数字化转型,浪潮携手腾讯推出SaaS服务新模式
下一篇:同心俱乐部常务副主席陈华旗下京基智农:在楼房里玩转数字化养猪

鲜花

握手

雷人

路过

鸡蛋

评论

您需要登录后才可以发表言论 登录立即注册
创宇盾启航版免费网站防御网站加速服务
投诉/建议联系

discuzaddons@vip.qq.com

未经授权禁止转载,复制和建立镜像,
如有违反,按照公告处理!!!
  • 联系QQ客服
  • 添加微信客服

联系DZ插件网微信客服|最近更新|Archiver|手机版|小黑屋|DZ插件网! ( 鄂ICP备20010621号-1 )|网站地图 知道创宇云防御

您的IP:18.222.96.135,GMT+8, 2024-12-29 04:53 , Processed in 0.150994 second(s), 43 queries , Gzip On, Redis On.

Powered by Discuz! X5.0 Licensed

© 2001-2024 Discuz! Team.

关灯
扫一扫添加微信客服
QQ客服返回顶部
返回顶部