MyBatis-Plus真实批量插入

394 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情

前言

总所周知,MyBatis-Plus 是一个 MyBatis的增强工具,只做增强不做改变,提供了很多通用的CRUD方法。

例如Service接口就提供了一个SaveBatch方法为我们提供批量插入,可能有人认为该方法就是会执行如下SQL语句

INSERT INTO table(id,name) VALUEs(1,"Tom"),(1,"Tom"),(1,"Tom")...

但如果你有留意MyBatis-Plus的DEBUG输出日志或者看过该方法的源码就知道,实际上还是一条条循环插入的。

源码

// ServiceImpl.java
@Transactional(
        rollbackFor = {Exception.class}
    )
    public boolean saveBatch(Collection<T> entityList, int batchSize) {
        String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);
        return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {
            sqlSession.insert(sqlStatement, entity);
        });
    }

内部实际上就是不断遍历entityList这个集合来实现“批量插入”这个功能,那为啥不提供真正的批量插入的功能呢?

根据作者的说法,这是由于不同数据库对于批量插入支持度不同的问题,那么如果我们要实现真正的批量插入有什么办法吗?

解决方法

手动拼接SQL

最显眼的办法无非就是自己进行SQL拼接,但这样工作量有点太大了,当一个表的字段过多时,还容易出现拼接问题。

官方内置方法(MySQL)

其实官方是提供了真正的批量插入方法,但目前只在MySQL数据库上进行测试过,如果我们的项目使用的数据库恰好是MySQL的话就可以配置该可选项。

首先创建一个SQL注入器配置类

@Component
public class SpiceSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList( mapperClass, tableInfo );
        methodList.add( new InsertBatchSomeColumn() ); // 添加批量插入方法
        return methodList;
    }
}

随后我们定义一个扩展BaseMapper的接口,例如下面的例子:

public interface SpiceBaseMapper<T> extends BaseMapper<T> {

    int insertBatchSomeColumn(List<T> entityList);
}

随后我们业务Mapper都需继承该SpiceBaseMapper接口,随后我们就可以正常调用该insertBatchSomeColumn方法了,通过日志的输出可以看到确实是真正的批量插入啦~

参考资料