Closed jackmiking closed 2 months ago
提供一下具体场景或代码
自动回复:你的邮件我已经收到,如果需要回复的我会尽快回复的。感谢你的谅解····
目前使用版本为3.5.5,使用updateBatchById更新多条数据时,只能拦截第一条更新SQL
应该不只是updateBatchById方法,所有与batch相关的方法在处理批量操作时,只会拦第一条数据 这个问题我也遇到了,有什么解决方法吗?
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不是同一个。
DataChangeRecorderInnerInterceptor可能在未来版本将会被移除,坑有点大
自动回复:你的邮件我已经收到,如果需要回复的我会尽快回复的。感谢你的谅解····
当前使用版本(必填,否则不予处理)
3.5.5
该问题是如何引起的?(确定最新版也有问题再提!!!)
在执行updateBatchById时,多个的数据更新,变动插件只能看到第一个数据
重现步骤(如果有就写完整)
报错信息
无