Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jackmiking opened this issue Mar 25, 2024 · 5 comments
Labels

Comments

@jackmiking
Copy link

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

3.5.5

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

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

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

  1. 执行iserice的updateBatchById的接口

报错信息

@Jasonyou-boy
Copy link

提供一下具体场景或代码

@jackmiking
Copy link
Author

jackmiking commented Mar 26, 2024 via email

@nieqiurong nieqiurong added the bug label Apr 11, 2024
@MrXiaoMo
Copy link

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

@CalmArrow
Copy link

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

@totoro52
Copy link

totoro52 commented Jun 3, 2024


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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants