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

3.5.5

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

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

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

  1. 执行iserice的updateBatchById的接口

报错信息

Comment From: Jasonyou-boy

提供一下具体场景或代码

Comment From: jackmiking

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

Comment From: MrXiaoMo

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

Comment From: CalmArrow

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

Comment From: totoro52

```

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不是同一个。

Comment From: VampireAchao

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

Comment From: jackmiking

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

Comment From: nieqiurong

6430

Comment From: cc1aymore

```

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不是同一个。

有问题,三次update后 ,mpSh.configuration().getEnvironment().getDataSource().getConnection(); 这里会卡死