mybatis-plus saveOrUpdateBatch踩坑记录
作者:Dango丶小七
这篇文章主要介绍了mybatis-plus saveOrUpdateBatch踩坑记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
mybatis-plus saveOrUpdateBatch踩坑
mybatis-plus版本: 3.5.1
调用方法
@Transactional(rollbackFor = Exception.class) default boolean saveOrUpdateBatch(Collection<T> entityList) { return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE); }
问题说明
当对entityList进行批量更新操作时,方法内部会根据主键查询该记录,导致批量更新操作十分缓慢
具体代码如下:
@Transactional(rollbackFor = Exception.class) @Override public boolean saveOrUpdateBatch(Collection<T> 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<T> param = new MapperMethod.ParamMap<>(); param.put(Constants.ENTITY, entity); sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); }); }
public static <E> boolean saveOrUpdateBatch(Class<?> entityClass, Class<?> mapper, Log log, Collection<E> list, int batchSize, BiPredicate<SqlSession, E> predicate, BiConsumer<SqlSession, E> 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 <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) { Assert.isFalse(batchSize < 1, "batchSize must not be less than one"); return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> { 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++; } }); }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。