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++;
}
});
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
