前言
? ? ? ? 使用Mybatis-plus可以很方便的實(shí)現(xiàn)批量新增和批量修改,不僅比自己寫foreach遍歷方便很多,而且性能也更加優(yōu)秀。但是Mybatis-plus官方提供的批量修改和批量新增都是根據(jù)id來修改的,有時(shí)候我們需求其他字段,所以就需要我們自己修改一下。
一、批量修改
? ? ? ? 在Mybatis-plus的IService接口中有updateBatchById方法,我們常用以下方法根據(jù)id批量修改數(shù)據(jù)。
@Transactional(rollbackFor = Exception.class)
default boolean updateBatchById(Collection<T> entityList) {
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID);
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
param.put(Constants.ENTITY, entity);
sqlSession.update(sqlStatement, param);
});
}
但是當(dāng)我們想根據(jù)其他字段批量修改數(shù)據(jù)時(shí),該方法就無能為力了。所以我們就可以根據(jù)第二個(gè)updateBatchById方法在自己的service類里面寫一個(gè)新的批量新增方法。
public boolean updateBatchByColumn(Collection<?> entityList, String idCard) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE);
return executeBatch(entityList, (sqlSession, entity) -> {
LambdaUpdateWrapper<SysUser> updateWrapper = Wrappers.<SysUser>lambdaUpdate()
.eq(SysUser::getIdCard, idCard);
Map<String, Object> param = CollectionUtils.newHashMapWithExpectedSize(2);
param.put(Constants.ENTITY, entity);
param.put(Constants.WRAPPER, updateWrapper);
sqlSession.update(sqlStatement, param);
});
}
注意sqlStatement是使用的SqlMethod.UPDATE,SysUser對(duì)象是舉例,使用的是若依的用戶數(shù)據(jù)。
二、批量新增或修改
? ? ? ? 在Mybatis-plus的ServiceImpl 類中有一個(gè)saveOrUpdateBatch 方法用于批量新增或修改,通過CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity))根據(jù)id查詢數(shù)據(jù)是否已存在,不存在新增,存在則修改,源碼如下:
@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);
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);
});
}
最終調(diào)用的是SqlHelper.saveOrUpdateBatch方法,該方法第六個(gè)參數(shù)是BiPredicate,這就是用于判斷數(shù)據(jù)庫中數(shù)據(jù)是否存在的關(guān)鍵,所以我們需要修改這個(gè)函數(shù)式接口,修改為根據(jù)其他條件查詢數(shù)據(jù)庫。該方法的第七個(gè)參數(shù)是BiConsumer,該函數(shù)式接口用于修改數(shù)據(jù),如果不想根據(jù)id修改數(shù)據(jù),可以參考第一部門進(jìn)行修改。
@Transactional(rollbackFor = Exception.class)
public boolean saveOrUpdateBatchByColumn(Collection<?> entityList, String idCard) {
return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, super.log, entityList, DEFAULT_BATCH_SIZE, (sqlSession, entity) -> {
LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.<SysUser>lambdaQuery()
.eq(SysUser::getIdCard, idCard);
Map<String, Object> map = CollectionUtils.newHashMapWithExpectedSize(1);
map.put(Constants.WRAPPER, queryWrapper);
return CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_LIST), map));
}, (sqlSession, entity) -> {
Map<String, Object> param = CollectionUtils.newHashMapWithExpectedSize(2);
param.put(Constants.ENTITY, entity);
sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
三、不使用Mybatis-plus進(jìn)行批量操作
? ? ? ? 有時(shí)候項(xiàng)目里沒有引用Mybatis-plus,但是也想進(jìn)行批量操作,數(shù)據(jù)量大了后foreach循環(huán)會(huì)影響性能。所以可以參考Mybatis-plus的批量操作,編寫在mybatis環(huán)境下的批量操作,代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-678320.html
@Component
public class MybatisBatchUtils {
private static final int BATCH_SIZE = 1000;
@Autowired
private SqlSessionFactory sqlSessionFactory;
public <T,U,R> boolean batchUpdateOrInsert(List<T> data, Class<U> mapperClass, BiFunction<T,U,R> function) {
int i = 1;
SqlSession batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
U mapper = batchSqlSession.getMapper(mapperClass);
int size = data.size();
for (T element : data) {
function.apply(element, mapper);
if ((i % BATCH_SIZE == 0) || i == size) {
batchSqlSession.flushStatements();
}
i++;
}
// 非事務(wù)環(huán)境下強(qiáng)制commit,事務(wù)情況下該commit相當(dāng)于無效
batchSqlSession.commit(!TransactionSynchronizationManager.isSynchronizationActive());
return true;
} catch (Exception e) {
batchSqlSession.rollback();
throw new RuntimeException(e);
} finally {
batchSqlSession.close();
}
}
}
寫在最后的話
? ? ? ? Mybatis-plus真好用,少寫好多代碼。有些不太適用的方法,也可以很簡(jiǎn)單在官方的基礎(chǔ)上進(jìn)行擴(kuò)展。文章來源地址http://www.zghlxwxcb.cn/news/detail-678320.html
到了這里,關(guān)于Mybatis-plus批量操作的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!