一个事务传播机制带来的生产事故

297 阅读2分钟

环境: jdk 8 框架: mybatis-plus mybaits

先问大家一个问题 下方代码新增 UserVisitor 表 已知 UserVisitor 唯一索引 phone、projectCode、userType 组成 执行后 UserVisitor 数据会保存哪一个手机号?还是都不会保存成功呢? 代码如下: image

很简单的几行代码,但是困扰了我一天~

先说结论:都不会保存成功,是由于 saveBatch 方法导致的数据回滚。

原因:

让我们看看 saveBatch 方法的实现 image 其实就是循环调用了 insert 方法 需要注意的是 saveBatch 方法上 额外声明了 Transactional 事务注解。并切 隔离机制是默认的 Propagation.REQUIRED 如果已有事务就沿用。 已知此时如果里面的方法执行出现错误 被 try 包裹了 理应是不会 rollback 但是!! 注意 如果又通过 aop 调用了下一级方法 并切传播依赖是 Propagation.REQUIRED 就会导致外层的事务也 回滚 !!!

ok 那在继续跟进 image image 手动 获取当前事务 并且 里层还有一个 catch 块 进行了事务回滚 按照事务传播机制 外层的数据也就被回滚了。

执行后的结果 image image 不过 注意下 mybatisPlus 的作者 的注释。3.3.1后面的版本 这个方法 会被替换

image

答疑: 如果 try 包裹后的方法 就算开启了事务 在下一集的方法栈 中 是否会导致 外层调用 rollback呢?

为了避免大家的疑问。给出下方测试案例

image 重载了一下 saveBacth 方法 外层test调用如下 image 执行结果如下 image 也是一样会回滚的~

~ 疑问解答 ~

解决方案: image 如果 改成 此模式进行 save 操作 并不会影响 调用方 uv表的数据写入

或者将事务传播依赖级别改成:REQUIRES_NEW

一道简单的 事务传播级别问题导致的问题~