+
 新版

mybatis-plus 批量插入时事务失效

osc_87307087 发布于 2021/10/26 16:27
阅读 5K+
收藏 1

各位大佬,小弟最近开发的时候碰到一个很诡异的问题,如下:

首先是一个接口,这个接口里面有两个方法,分别是方法A和方法B,在方法A中使用mybatis-plus提供的批量插入API,saveOrUpdateBatch,成功批量插入了C表数据,然后在方法B中查询方法A批量插入的C表数据,发现查不到,然后拿日志打印的查询语句去数据库执行,是可以查到数据的。

之后,我尝试着在方法A中把批量插入改成for循环一个一个插入,然后方法B不变,这回就可以查询到A方法中插入的C表数据了。

事后,小弟排除了很多可能,包括方法B的查询条件是否错误,方法A批量插入的数据是否有误,包括事务配置,这些均没有发现有不对的地方,不知道是我哪里配置不对,还是mybatis-plus本身的问题。

加载中
1
魔力猫
魔力猫

继续检查事务配置,包括你程序事务设定和数据库隔离等级,这个问题大概率是A和B不在一个事务。A执行后还没有提交事务,B就执行了,所以B查不到A的。

你一个个插入,那可能就是插1个提交了一次事务,于是B就拿到了。

0
sprouting
sprouting

不确定你的具体配置,但可能有这么几个问题

1,做了主从分离,查询的时候从库还没有同步,等你复制好语句的时候从库已经同步了

2、事务,你的A方法和B方法不再同一个事务之中导致的。也可能你的A方法和B方法采用的事务策略是新建事务,导致查不到

 

魔力猫
魔力猫
我认为主从分离的可能性不大,因为问题的标签上是Oracle而不是MySQL。Oracle有钱做主从分离,那干嘛不干脆再稍微加一点,直接RAC?!
0
_Mr_Right_
_Mr_Right_

mybatis-plus本身的问题概率不大,因为你的描述是常见需求,要出问题早出问题了。

其次,你可以吧你的代码脱敏,贴出来,大家一起集思广益。

0
osc_87307087
osc_87307087
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="search*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="del*" rollback-for="java.lang.Exception"/>
        <tx:method name="delete*" rollback-for="java.lang.Exception"/>
        <tx:method name="insert*" rollback-for="java.lang.Exception"/>
        <tx:method name="update*" rollback-for="java.lang.Exception"/>
        <tx:method name="save*" rollback-for="java.lang.Exception"/>
        <tx:method name="*" rollback-for="java.lang.Exception"/>
    </tx:attributes>
</tx:advice>

这个是事务的部分配置,有尝试在在name="*"的那一行加上

propagation="SUPPORTS"

也是不生效。

以下是相关的代码:

最外层的接口:

// 拷贝申请材料数据
wxHandinMatService.copyTrMatBasToWechat(applyId, busType, applyInfo.getSenderOrigin(), applyUserId);
// 根据业务内容重置必上传属性
wxHandinMatService.resetHandinMatIsEss(applyId, busType);

A方法:

@Override
    public void copyTrMatBasToWechat(String applyId, String busType, String senderOrigin, String applyUserId) {
        List<WxHandinMat> handinMats = listHandinMat(applyId, busType, false);
        // 如果为空,则拷贝
        if (CollectionUtils.isEmpty(handinMats)) {
            // TODO
            List<TrMatBas> trMatBasList = trMatBasService.listByBusType(busType, senderOrigin);
            if (!CollectionUtils.isEmpty(trMatBasList)) {
                List<WxHandinMat> list = new ArrayList<>();
                for (TrMatBas matBas : trMatBasList) {
                    WxHandinMat handinMat = new WxHandinMat();
                    // TODO
                    list.add(handinMat);
                }
                // 这里批量插入之后,B方法查询不到
                if (!CollectionUtils.isEmpty(list)) {
//                    for (WxHandinMat handinMat : list) {
//                        saveOrUpdate(handinMat); // 单独一个一个插入,B方法可以查询到
//                    }
                    saveOrUpdateBatch(list);
                }
            }
        }
    }

B方法:

@Override
public void resetHandinMatIsEss(String applyId, String busType) {
    List<WxHandinMat> wxHandinMats = listHandinMat(applyId, busType, false);
    if (!CollectionUtils.isEmpty(wxHandinMats)) {
        // TODO
    }
}
osc_87307087
osc_87307087
A方法和B方法都是同一个service的不同接口 A方法中的List<WxHandinMat> handinMats = listHandinMat(applyId, busType, false);和B方法中的List<WxHandinMat> wxHandinMats = listHandinMat(applyId, busType, false);是同一个接口
0
飞奔地蜗牛
飞奔地蜗牛

问题多半在这个listHandinMat方法里面。仔细检查代码把,多半是一些低级的问题导致的。

 
osc_87307087
osc_87307087
listHandinMat只是一个简单的QueryWrapper条件查询,倒没看到有什么问题:joy:
0
我家有猪
我家有猪
saveOrUpdateBatch的时候指定batchSize
osc_87307087
osc_87307087
试了下,还是不行
0
ducat7
ducat7

1、saveOrUpdateBatch(…)方法也是循环生成insert语句,你可以优化成一条insert语句(这是MyBatis优势之一)。

2、先插后查不到,不在一个session里、DB就没及时处理等有关。

3、MyBatis里的方法都是一个方法一个事务,所以,不在一个session管道里。(JPA不注解也是如此)

 

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部