baomidou / mybatis-plus

An powerful enhanced toolkit of MyBatis for simplify development
https://baomidou.com
Apache License 2.0
16.41k stars 4.31k forks source link

数据变动记录插件在执行updateBatchById方法时,只能得到第一条,后续的数据无法记录 #6018

Closed jackmiking closed 2 months ago

jackmiking commented 7 months ago

当前使用版本(必填,否则不予处理)

3.5.5

该问题是如何引起的?(确定最新版也有问题再提!!!)

在执行updateBatchById时,多个的数据更新,变动插件只能看到第一个数据

重现步骤(如果有就写完整)

  1. 执行iserice的updateBatchById的接口

报错信息

Jasonyou-boy commented 7 months ago

提供一下具体场景或代码

jackmiking commented 7 months ago

自动回复:你的邮件我已经收到,如果需要回复的我会尽快回复的。感谢你的谅解····

MrXiaoMo commented 6 months ago

目前使用版本为3.5.5,使用updateBatchById更新多条数据时,只能拦截第一条更新SQL WechatIMG4

CalmArrow commented 6 months ago

应该不只是updateBatchById方法,所有与batch相关的方法在处理批量操作时,只会拦第一条数据 这个问题我也遇到了,有什么解决方法吗?

totoro52 commented 5 months ago

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.plugins.inner.DataChangeRecorderInnerInterceptor;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author Totoro
 * @date 2024/6/3
 * @description
 **/
public class CustomDataChangeInnerInterceptor extends DataChangeRecorderInnerInterceptor  {

    @Override
    public void beforeGetBoundSql(StatementHandler sh) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        // 补充connection
        Connection connection;
        try {
            connection = mpSh.configuration().getEnvironment().getDataSource().getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        MappedStatement ms = mpSh.mappedStatement();
        final BoundSql boundSql = mpSh.boundSql();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            OperationResult operationResult;
            long startTs = System.currentTimeMillis();
            try {
                Statement statement = JsqlParserGlobal.parse(mpBs.sql());
                if (statement instanceof Insert) {
                    operationResult = processInsert((Insert) statement, mpSh.boundSql());
                } else if (statement instanceof Update) {
                    operationResult = processUpdate((Update) statement, ms, boundSql, connection);
                } else if (statement instanceof Delete) {
                    operationResult = processDelete((Delete) statement, ms, boundSql, connection);
                } else {
                    logger.info("other operation sql={}", mpBs.sql());
                    return;
                }
            } catch (Exception e) {
                if (e instanceof DataUpdateLimitationException) {
                    throw (DataUpdateLimitationException) e;
                }
                logger.error("Unexpected error for mappedStatement={}, sql={}", ms.getId(), mpBs.sql(), e);
                return;
            }
            long costThis = System.currentTimeMillis() - startTs;
            if (operationResult != null) {
                operationResult.setCost(costThis);
                dealOperationResult(operationResult);
            }
        }
    }

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        // 我什么都不干
    }

}

看了下源代码,InnerInterceptor#beforePrepare这个方法一般作用是修改执行的SQL,但这个插件有点特殊,它还需要回查数据,但beforePrepare只拿到了首条数据,因为最终去执行的是updateById方法。能拿到的数据很有限,所以我也没想到好点解决的方法。。 你可以先用这个方法暂时解决问题,其实就是把beforePrepare的代码搬到beforeGetBoundSql方法,需要注意的是这里的connection不是同一个。

VampireAchao commented 2 months ago

DataChangeRecorderInnerInterceptor可能在未来版本将会被移除,坑有点大

jackmiking commented 2 months ago

自动回复:你的邮件我已经收到,如果需要回复的我会尽快回复的。感谢你的谅解····

nieqiurong commented 2 months ago

6430