我希望数据能根据name和content作为唯一索引,如果 数据库中的数据, name和content相同,就更新记录,如果不同,就插入记录。
废话不多说,直接上代码。
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveOrUpdateBatch(Collection<FulfillmentItem> entityList) {
return SqlHelper.saveOrUpdateBatch(
this.getEntityClass(),
this.currentMapperClass(),
super.log,
entityList,
DEFAULT_BATCH_SIZE,
(sqlSession, entity) -> {
Wrapper<FulfillmentItem> queryWrapper = Wrappers.<FulfillmentItem>lambdaQuery()
.eq(FulfillmentItem::getName, entity.getName())
.eq(FulfillmentItem::getContent, entity.getContent());
Map<String, Object> map = new HashMap<>();
map.put(Constants.WRAPPER, queryWrapper);
return CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_LIST), map));
},
(sqlSession, entity) -> {
Wrapper<FulfillmentItem> lambdaUpdateWrapper = Wrappers.lambdaUpdate(FulfillmentItem.class)
.eq(FulfillmentItem::getName, entity.getName())
.eq(FulfillmentItem::getContent, entity.getContent());
Map<String, Object> map = new HashMap<>();
map.put(Constants.ENTITY, entity);
map.put(Constants.WRAPPER, lambdaUpdateWrapper);
sqlSession.update(getSqlStatement(SqlMethod.UPDATE), map);
});
}
注意点:
saveOrUpdateBatch 本质是先查后改,高并发业务请谨慎取用。
mybatis 旧版本略有不同,没有 this.getEntityClass() 方法。
原因是旧版本中,entityClass 属性是 protectd 类型,可以直接用,
springboot 3 后的版本,改成了 private 类型。
源码:
private Class<T> entityClass; // 旧版本是 protected类型
public Class<T> getEntityClass() {
if (this.entityClass == null) {
this.entityClass = GenericTypeUtils.resolveTypeArguments(this.getMapperClass(), BaseMapper.class)[0];
}
当然,这里也可以根据 name 和 content 作为唯一索引,用 MySQL 的 ON DUPLICATE KEY UPDATE 来做判断。
但是由于我content是text类型,无法用作索引列。
如果高并发下,非要用 DUPLICATE KEY UPDATE,可以加一列:content_hash.
通过存储 content 内容的哈希值,来做唯一索引,也能解决这个问题。