Mybatis-Plus根据其他字段批量保存或更新

4,407 阅读2分钟

1. Mybatis-Plus根据其他字段批量保存或更新

业务背景:经常要同步其他系统的数据过来,而且需要使用雪花id替代别人的表中的主键,所以增量同步的时候需要考虑其他字段来判断是更新还是保存

2. 谈谈mybatis-plus的saveOrUpdateBatch方法


#com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveOrUpdateBatch
    @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);
            
            // 这里的lambda表达是就是SqlHelper#saveOrUpdateBatch方法中的BiPredicate<SqlSession, E> predicate  
            // 判断id值为空,或者根据id查询不到数据的情况下,就执行插入操作,否则就执行下面的更新操作
            return StringUtils.checkValNull(idVal)
                || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
        }, (sqlSession, entity) -> {
            // 这里的lambda表达是就是SqlHelper#saveOrUpdateBatch方法中的BiPredicate<SqlSession, E> predicate, BiConsumer<SqlSession, E> consumer 
            // 执行更新操作
            MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
            param.put(Constants.ENTITY, entity);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
        });
    }


# com.baomidou.mybatisplus.extension.toolkit.SqlHelper#saveOrUpdateBatch
    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) -> {
            if (predicate.test(sqlSession, entity)) {
                sqlSession.insert(sqlStatement, entity);
            } else {
                consumer.accept(sqlSession, entity);
            }
        });
    }

所以要想换成根据其他字段保存更新或者保存,

保存的话就只需要将lambda中的判断条件改成根据其他字段查询是否有数据,有就保存。没有就更新

更新这里这里还有个细节,因为是根据其他字段更新,所以原来的方法就不能直接使用了,因为原来的方法是已根据id更新。

3. 重写IService和ServiceImpl

public interface EnhancedService<T> extends IService<T> {

    boolean saveOrUpdateBatchByColumn(Collection<T> entityList, Function<T, LambdaQueryWrapper<T>> function);
}

public class EnhancedServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {

    /**
     * 可以根据其他字段批量更新或新增
     *
     * @param entityList 数据集合
     * @param function   新增或者更新判断条件
     * @return 操作结果
     */
    public boolean saveOrUpdateBatchByColumn(Collection<T> entityList, Function<T, LambdaQueryWrapper<T>> function) {
        return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, DEFAULT_BATCH_SIZE, (sqlSession, entity) -> {
            Map<String, Object> param = Maps.newHashMap();
            param.put(Constants.ENTITY, entity);
            param.put(Constants.WRAPPER, function.apply(entity));
            return CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_MAPS), param));
        }, (sqlSession, entity) -> {
            Map<String, Object> param = Maps.newHashMap();
            param.put(Constants.ENTITY, entity);
            param.put(Constants.WRAPPER, function.apply(entity));
            sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE), param);
        });
    }

}

4. 使用如下

实体类如下

public class User implements Serializable {

    private static final long serialVersionUID = 1L;

	//雪花id
    @TableId
    private Long id;

    private String age;

    private String code;

    private String name;

    private String other1;

    private String other2;

    private String other3;

    private Integer fillType;
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

}

比如你想根据 name,code,age三个字段来更新。

首先你得userService要实现EnhancedServiceImpl

public interface UserService extends EnhancedService<User> {

@Service
public class UserServiceImpl extends EnhancedServiceImpl<UserMapper, User> implements UserService {
}

示例代码如下:

 userService.saveOrUpdateBatchByColumn(Arrays.asList(user1, user2),
                item -> Wrappers.lambdaQuery(User.class)
                        .eq(User::getName, item.getName())
                        .eq(User::getCode, item.getCode())
                        .eq(User::getAge, item.getAge())
        );