/**
* 根据wrapper 批量更新
*
* @param ewList wrapper对象集合
* @return boolean
* @since 3.5.6 日期:2024-06-11
*/
@Transactional(rollbackFor = Exception.class)
public boolean updateMulti(Collection<? extends Wrapper<T>> ewList) {
return updateMulti(ewList, DEFAULT_BATCH_SIZE);
}
/**
* 根据wrapper 批量更新
*
* @param ewList wrapper对象集合
* @param batchSize 更新批次数量
* @return boolean
* @since 3.5.6 日期:2024-06-11
*/
@Transactional(rollbackFor = Exception.class)
public boolean updateMulti(Collection<? extends Wrapper<T>> ewList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE);
return executeBatch(ewList, batchSize, (sqlSession, ew) -> {
MapperMethod.ParamMap<Wrapper<T>> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, null);
param.put(Constants.WRAPPER, ew);
sqlSession.update(sqlStatement, param);
});
}
/**
* 根据ID 批量更新
*
* @param entityList 实体对象集合
* @return boolean
* @since 3.5.6 日期:2024-06-11
*/
@Transactional(rollbackFor = Exception.class)
public boolean upsertMulti(Collection<T> entityList) {
return upsertMulti(entityList, DEFAULT_BATCH_SIZE);
}
/**
* 根据ID 批量修改插入
*
* @param entityList 实体对象集合
* @param batchSize 更新批次数量
* @return boolean
* @since 3.5.6 日期:2024-06-11
*/
@Transactional(rollbackFor = Exception.class)
public boolean upsertMulti(Collection<T> entityList, int batchSize) {
if (CollectionUtils.isEmpty(entityList)) return false;
TableInfo tableInfo = TableInfoHelper.getTableInfo(getEntityClass());
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!");
String selectSqlStatement = getSqlStatement(SqlMethod.SELECT_OBJS);
String insertSqlStatement = getSqlStatement(SqlMethod.INSERT_ONE);
String updateSqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
Consumer<SqlSession> consumer = sqlSession -> {
int size = entityList.size();
int idxLimit = Math.min(batchSize, size);
int i = 1;
// 批处理临时集合
List<T> batchList = new ArrayList<>();
for (T element : entityList) {
batchList.add(element);
// 批处理
if (i == idxLimit) {
// 批数据id集合
List<Object> idList = batchList.stream()
.map(e -> tableInfo.getPropertyValue(e, keyProperty))
.filter(StringUtils::checkValNotNull)
.toList();
// 查询批数据中已存在的id集合
List<Object> existedIdList = null;
if (!idList.isEmpty()) {
Map<String, Object> params = new HashMap<>();
params.put(Constants.WRAPPER, Wrappers.query().select(keyProperty).in(keyProperty, idList));
existedIdList = sqlSession.selectList(selectSqlStatement, params);
}
// 遍历批数据
for (T entity : batchList) {
Object id = tableInfo.getPropertyValue(entity, keyProperty);
if (StringUtils.checkValNull(id) || CollectionUtils.isEmpty(existedIdList) || !existedIdList.contains(id)) {
sqlSession.insert(insertSqlStatement, entity);
} else {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(updateSqlStatement, param);
}
}
// 提交sql
sqlSession.flushStatements();
idxLimit = Math.min(idxLimit + batchSize, size);
// 清空已处理的数据
batchList.clear();
}
i++;
}
};
return SqlHelper.executeBatch(getSqlSessionFactory(), log, consumer);
}
旧版每个对象都会查询校验一遍,效率极低。还有就是校验数据是否存在,为啥用selectById,而不是用count查询校验?
Comment From: sgps000
由于之前使用mongodb设计的原因,实体类中特殊类型都会重写get方法,导致有些字段永远不会为空,直接使用entity类型的更新容易出错,所以更多的是想要通过wrapper去主动精准地操作数据库。原本还想实现一个基于wrapper的批量修改插入的,但是想到批量校验需要在java中,通过wrapper直接校验对象是否符合条件,暂时没找到合适的办法,只能用MERGE INTO语句自定义注入器去实现基础功能,没法像mongodb的upsert那样方便。
Comment From: nieqiurong
6229
Comment From: nieqiurong
自己业务代码自己处理,不要什么都希望框架帮你做.
Comment From: sgps000
自己业务代码自己处理,不要什么都希望框架帮你做.
@nieqiurong
第一个方法是基于wrapper批量更新,如果算个人业务我能理解。
但第二个批量更新插入,我感觉是框架代码的写法有问题,建议改掉。
原框架中serviceImpl的saveOrUpdateBatch那么慢,3.5.7的BaseMapper中InsertOrUpdate也没有改变写法,是用的人少才没人反馈吗?还是我的用法错了?
Comment From: sgps000
关于第一个方法,我是在想既然update(Wrapper
Comment From: agibso38
确实saveOrUpdateBatch好慢,为什么不先批量查出来比对后在批量新增或修改