插件窝 干货文章 MyBatis 批量插入时拦截器失效如何解决?

MyBatis 批量插入时拦截器失效如何解决?

拦截器 批量 操作 Executor 209    来源:    2025-03-31

MyBatis 批量插入时拦截器失效问题解决方案

问题分析

MyBatis 拦截器在批量插入操作时失效通常是由于以下原因:

  1. Executor 类型问题:批量操作通常使用 BatchExecutor,而拦截器可能只配置了对 SimpleExecutor 或 ReuseExecutor 生效
  2. SQL 语句生成方式:批量插入可能使用了特殊的 SQL 生成方式绕过拦截器
  3. 拦截器配置范围:拦截器可能没有正确配置拦截批量操作相关的方法

解决方案

1. 确保拦截器配置正确

@Intercepts({
    @Signature(type = Executor.class, 
               method = "update", 
               args = {MappedStatement.class, Object.class})
})
public class MyInterceptor implements Interceptor {
    // 拦截器实现
}

确保你的拦截器签名包含所有可能的 Executor 类型。

2. 检查 Executor 类型

批量操作通常使用 BatchExecutor,确保你的拦截器能处理这种类型:

@Intercepts({
    @Signature(type = Executor.class, 
               method = "update", 
               args = {MappedStatement.class, Object.class}),
    @Signature(type = Executor.class, 
               method = "flushStatements", 
               args = {})
})
public class MyBatchInterceptor implements Interceptor {
    // 拦截器实现
}

3. 处理批量操作的特殊情况

在拦截器中添加对批量操作的判断:

@Override
public Object intercept(Invocation invocation) throws Throwable {
    Object[] args = invocation.getArgs();
    MappedStatement ms = (MappedStatement) args[0];
    Object parameter = args[1];

    // 判断是否为批量操作
    if (parameter instanceof Collection) {
        // 处理批量逻辑
        Collection<?> collection = (Collection<?>) parameter;
        for (Object obj : collection) {
            // 对每个对象进行处理
        }
    }

    return invocation.proceed();
}

4. 配置 SqlSessionFactory 使用正确的 Executor

确保你的 SqlSessionFactory 配置了支持拦截器的 Executor:

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(dataSource);

    // 设置Executor类型,如果需要支持批量操作
    org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
    configuration.setDefaultExecutorType(ExecutorType.BATCH);
    sessionFactory.setConfiguration(configuration);

    // 添加拦截器
    sessionFactory.setPlugins(new Interceptor[]{new MyBatchInterceptor()});

    return sessionFactory.getObject();
}

5. 检查批量插入的实现方式

如果你使用的是 MyBatis 的 foreach 标签进行批量插入,确保拦截器能处理这种 SQL 构建方式:

<insert id="batchInsert" parameterType="java.util.List">
    INSERT INTO table_name (column1, column2)
    VALUES
    <foreach collection="list" item="item" separator=",">
        (#{item.field1}, #{item.field2})
    </foreach>
</insert>

验证步骤

  1. 在拦截器中添加日志,确认是否被调用
  2. 检查批量操作时传入的参数类型
  3. 确保拦截器的 @Intercepts 注解覆盖了所有需要拦截的方法
  4. 测试不同 ExecutorType 下的拦截效果

如果以上方法仍不能解决问题,可能需要检查 MyBatis 版本是否存在已知问题,或考虑使用其他方式实现批量操作时的逻辑处理。