提高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俱乐部。