mysql小技能:批量插入性能优化

242 阅读1分钟

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

引言

mybatis-plus内置的批量插入方法saveBatch并不是真正的批量写入,而是通过executeBatch分批提交。

    boolean saveBatch(Collection<T> entityList, int batchSize);

所以想提升批量插入的性能可以采用多值插入。

多值插入的方式1: JDBC URL批量处理参数配置, 在mysql连接信息中添加rewriteBatchedStatements=true使得执行效率大幅提升。

多值插入的方式2: 通过sql注入器注入InsertBatchSomeColumn方法实现了insert的多值插入,提升了批量插入的性能。

I JDBC URL批量处理参数配置【推荐】

useServerPrepStmts = false& rewriteBatchedStatements = true

  1. useServerPrepStmts 参数影响数据精度
  2. 配置rewriteBatchedStatements=true,在调用 executeBatch() 批量执行 INSERT语句时,mysql内部会自动将批量提交的sql重写为insert多值插入再执行。

批量sql重写开关参数rewriteBatchedStatements默认是关闭的,mysql连接驱动器版本3.1.13以后支持该配置

II 重写saveBatch实现多值插入

通过sql注入器注入InsertBatchSomeColumn方法实现了insert的多值插入,提升了批量插入的性能。

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;
    /**
     *
     * @param entityList
     * @param batchSize
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean saveBatch(Collection<User> entityList, int batchSize) {
        try {
            int size = entityList.size();
            int idxLimit = Math.min(batchSize, size);
            int i = 1;
            //保存单批提交的数据集合
            List<User> oneBatchList = new ArrayList<>();
            for(Iterator<User> var7 = entityList.iterator(); var7.hasNext(); ++i) {
                User element = var7.next();
                oneBatchList.add(element);
                if (i == idxLimit) {
                    userMapper.insertBatchSomeColumn(oneBatchList);
                    //每次提交后需要清空集合数据
                    oneBatchList.clear();
                    idxLimit = Math.min(idxLimit + batchSize, size);
                }
            }
        }catch (Exception e){
            log.error("saveBatch fail",e);
            return false;
        }
        return  true;
    }

}