背景
A系统的数据往B系统同步,订单主表、订单子表,一对多的关系。当订单发生修改,在同步子表数据的时候,如果子表数据多了或者少了的情况,逻辑是
1、表里多的数据,删掉(本文示例做的是物理删除,可根据需求进行修改)
2、表里少的数据,插入
3、相同的数据,更新
为了方便使用,写了个共通的方法,需要的供参考
代码
两个方法支持相同实体、不相同实体
/**
* 相同表merge
*
* @param list 从表里查出来的数据
* @param getKeyFunction 获取T的唯一标识
* @param mapperClass T的mapper
* @param wrapper T的更新条件
* @param <T>
*/
@DSTransactional
public <T> void mergeData(List<T> list, List<T> sourceList, Function<T, Object> getKeyFunction, Class mapperClass, Function<T, Wrapper> wrapper) {
// 找多的数据,删除(list有,sourceList没有)
List<T> deleteList = list.stream()
.filter(item -> sourceList.stream().noneMatch(syncItem -> getKeyFunction.apply(syncItem).equals(getKeyFunction.apply(item))))
.collect(Collectors.toList());
if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(deleteList)) {
DynamicBatchSqlUtil.batchDelete(deleteList, mapperClass, wrapper);
}
// 找相同的数据,更新(list有,sourceList有)
List<T> updateList = list.stream()
.filter(item -> sourceList.stream().anyMatch(syncItem -> getKeyFunction.apply(syncItem).equals(getKeyFunction.apply(item))))
.collect(Collectors.toList());
if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(updateList)) {
DynamicBatchSqlUtil.batchUpdate(updateList, mapperClass, wrapper);
}
// 找Sync新增的数据(list没有,sourceList有)
List<T> insertList = sourceList.stream()
.filter(item -> list.stream().noneMatch(syncItem -> getKeyFunction.apply(syncItem).equals(getKeyFunction.apply(item))))
.collect(Collectors.toList());
if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(insertList)) {
DynamicBatchSqlUtil.batchInsert(insertList, mapperClass);
}
list.addAll(insertList);
}
/**
* 两个不同的表merge
*
* @param list 从表里查出来的数据
* @param syncList 需要merge到表里的数据
* @param syncFunction R转T
* @param getKeyFunction 获取T的唯一标识
* @param mapperClass T的mapper
* @param wrapper T的更新条件
* @param <T>
* @param <R>
*/
public <T, R> void mergeData(List<T> list, List<R> syncList, Function<R, T> syncFunction, Function<T, Object> getKeyFunction, Class mapperClass, Function<T, Wrapper> wrapper) {
// 先把数据转成一样的
List<T> sourceList = syncList.stream().map(syncFunction).collect(Collectors.toList());
mergeData(list, sourceList, getKeyFunction, mapperClass, wrapper);
}
DynamicBatchSqlUtil
@Component
public class DynamicBatchSqlUtil {
private static String defaultDsKey;
public static final String SQL_TYPE_INSERT = "INSERT";
public static final String SQL_TYPE_UPDATE = "UPDATE";
public static final String SQL_TYPE_DELETE = "DELETE";
/**
* 给静态变量赋值
*
* @param defaultDsKey
*/
@Value("${spring.datasource.dynamic.primary}")
public void setDefaultDsKey(String defaultDsKey) {
this.defaultDsKey = defaultDsKey;
}
/**
* 批量插入
*
* @param list 数据
* @param mapperClass 执行数据的mapper的CLass
* @return
*/
public static <T> int batchInsert(List<T> list, Class mapperClass) {
DS ds = (DS) mapperClass.getAnnotation(DS.class);
// Mapper没有注解,就使用默认的
String dsKey = ds != null ? ds.value() : defaultDsKey;
return batchInsert(SQL_TYPE_INSERT, dsKey, list, mapperClass, null);
}
/**
* 批量更新
*
* @param list 数据
* @param mapperClass 执行数据的mapper的CLass
* @return
*/
public static <T> int batchUpdate(List<T> list, Class mapperClass, Function<T, Wrapper> wrapper) {
DS ds = (DS) mapperClass.getAnnotation(DS.class);
// Mapper没有注解,就使用默认的
String dsKey = ds != null ? ds.value() : defaultDsKey;
return batchInsert(SQL_TYPE_UPDATE, dsKey, list, mapperClass, wrapper);
}
/**
* 批量删除
*
* @param list 数据
* @param mapperClass 执行数据的mapper的CLass
* @return
*/
public static <T> int batchDelete(List<T> list, Class mapperClass, Function<T, Wrapper> wrapper) {
DS ds = (DS) mapperClass.getAnnotation(DS.class);
// Mapper没有注解,就使用默认的
String dsKey = ds != null ? ds.value() : defaultDsKey;
return batchInsert(SQL_TYPE_DELETE, dsKey, list, mapperClass, wrapper);
}
/**
* 批量插入
*
* @param type sql类型
* @param dsKey 数据源
* @param list 数据
* @param mapperClass 执行数据的mapper的CLass
* @return
*/
public static <T> int batchInsert(String type, String dsKey, List<T> list, Class mapperClass, Function<T, Wrapper> wrapper) {
DynamicDataSourceContextHolder.push(dsKey);
try {
return SQL_TYPE_INSERT.equals(type) ? batchInsertExecute(list, mapperClass)
: SQL_TYPE_UPDATE.equals(type) ? batchUpdateExecute(list, mapperClass, wrapper)
: SQL_TYPE_DELETE.equals(type) ? batchDeleteExecute(list, mapperClass, wrapper) : 0;
} finally {
DynamicDataSourceContextHolder.poll();
}
}
/**
* 批量插入
*
* @param list
* @param mapperClass
* @return
*/
public static <T> int batchInsertExecute(List<T> list, Class mapperClass) {
SqlSessionFactory sqlSessionFactory = SpringUtils.getBean("sqlSessionFactory");
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
Object mapper = sqlSession.getMapper(mapperClass);
list.forEach(((MyBaseMapper) mapper)::insert);
sqlSession.flushStatements();
sqlSession.commit();
}
return list.size();
}
/**
* 批量更新
*
* @param list
* @param mapperClass
* @param wrapper 更新条件
* @return
*/
public static <T> int batchUpdateExecute(List<T> list, Class mapperClass, Function<T, Wrapper> wrapper) {
SqlSessionFactory sqlSessionFactory = SpringUtils.getBean("sqlSessionFactory");
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
Object mapper = sqlSession.getMapper(mapperClass);
list.forEach(obj -> {
((MyBaseMapper) mapper).update(obj, wrapper.apply(obj));
});
sqlSession.flushStatements();
sqlSession.commit();
}
return list.size();
}
/**
* 批量删除
*
* @param list
* @param mapperClass
* @param wrapper 删除条件
* @return
*/
public static <T> int batchDeleteExecute(List<T> list, Class mapperClass, Function<T, Wrapper> wrapper) {
SqlSessionFactory sqlSessionFactory = SpringUtils.getBean("sqlSessionFactory");
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
Object mapper = sqlSession.getMapper(mapperClass);
list.forEach(obj -> {
((MyBaseMapper) mapper).delete(wrapper.apply(obj));
});
sqlSession.flushStatements();
sqlSession.commit();
}
return list.size();
}
}
参考:
Jdk8函数接口Supplier、Function、Predicate、Consumer、BiFunction、BiPredicate、BiConsumer