IT俱乐部 Java 怎样提高mybatis-plus中saveBatch方法的效率

怎样提高mybatis-plus中saveBatch方法的效率

提高mybatis-plus中saveBatch方法的效率

MyBatis-Plus中的saveBatch方法是一个很方便的批量插入数据的方法,但是如果插入的数据量很大时,可能会出现效率较低的情况。

提高saveBatch方法效率的方法

1.批量插入的数据量不宜过大,否则可能会导致内存溢出。建议根据实际情况选择合适的批量插入数据的数量。

2.如果插入的数据是从文件或其他数据源中读取的,可以使用流式插入的方式,将数据流分批插入数据库,可以减小内存压力。

3.在执行saveBatch方法前,可以通过开启MyBatis-Plus的批量插入功能,将多条SQL语句合并成一条执行,减少与数据库的交互次数。可以通过以下代码开启批

mybatis-plus saveOrUpdateBatch踩坑

mybatis-plus版本: 3.5.1

调用方法

@Transactional(rollbackFor = Exception.class)  
default boolean saveOrUpdateBatch(Collection entityList) {  
    return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);  
}

问题说明

当对entityList进行批量更新操作时,方法内部会根据主键查询该记录,导致批量更新操作十分缓慢,具体代码如下

@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection entityList, int batchSize) {
    TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
    Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
    String keyProperty = tableInfo.getKeyProperty();
    Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
    return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {
        Object idVal = tableInfo.getPropertyValue(entity, keyProperty);
        // 当主键存在时,会执行sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity)查询该条记录
        return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
    }, (sqlSession, entity) -> {
        MapperMethod.ParamMap param = new MapperMethod.ParamMap();
        param.put(Constants.ENTITY, entity);
        sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
    });
}
public static  boolean saveOrUpdateBatch(Class> entityClass, Class> mapper, Log log, Collection list, int batchSize, BiPredicate predicate, BiConsumer consumer) {
    String sqlStatement = getSqlStatement(mapper, SqlMethod.INSERT_ONE);
    return executeBatch(entityClass, log, list, batchSize, (sqlSession, entity) -> {
        // 执行predicate
        if (predicate.test(sqlSession, entity)) {
            sqlSession.insert(sqlStatement, entity);
        } else {
            consumer.accept(sqlSession, entity);
        }
    });
}
public static  boolean executeBatch(Class> entityClass, Log log, Collection list, int batchSize, BiConsumer consumer) {
    Assert.isFalse(batchSize  {
        int size = list.size();
        int idxLimit = Math.min(batchSize, size);
        int i = 1;
        for (E element : list) {
            // 循环每条记录,执行consumer,在此次调用中,consumer中会执行predicate,当该条记录主键不为空时,会通过主键查询该记录
            consumer.accept(sqlSession, element);
            if (i == idxLimit) {
                sqlSession.flushStatements();
                idxLimit = Math.min(idxLimit + batchSize, size);
            }
            i++;
        }
    });
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持IT俱乐部。

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/java/8754.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部