重新 mybatis plus 的 撒着OrUpdate 方法,实现根据自定义字段插入或者修改
我希望数据能根据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 内容的哈希值,来做唯一索引,也能解决这个问题。