1. 背景
批量查询,如何入参数组参数过多,会导致SQL长度过长,数据库会拒绝查询
2. 解决方式
在代码的层面上,进行分批查询,例如2000个参数,分成1000一批来进行查询,但是又会有几个问题
- 不同类的查询,入参和出参均不同,有没有一种方式,可以兼容不同的出入参
- 全量查询sql会去重,分批查询,不同批次会查出重复的数据,如何去重
3. 编程代码
通过函数式编程,封装函数,根据不同的查询,传入不同的查询类,就不用每个方式单独写一次
新建函数式函数式接口
@FunctionalInterface
public interface DatabaseOperation<T, R> {
/**
* 分批操作
*
* @param partition
* @return
*/
R apply(List<T> partition);
}
封装函数
/**
* 分批次操作(增、删、改、查),最后合并结果 解决2048 问题,
*
* @param inputList 所有查询的列表
* @param maxSize 分割数
* @param operation mapper查询操作
* @param distinctByKey 唯一值,用于去重,避免分批查询合并得结果有重复数据
* @param <T>
* @param <R>
* @return
*/
public static <T, R> List<R> executeInPartitions(List<T> inputList, int maxSize,
DatabaseOperation<T, List<R>> operation,
Function<? super R, ?> distinctByKey) {
// 使用LinkedHashMap保留插入顺序,在去重时将会用到
Map<Object, R> map = new LinkedHashMap<>();
if (inputList == null || inputList.isEmpty()) {
return new ArrayList<>(map.values());
}
// 将输入列表根据最大大小切割并执行操作
for (int i = 0; i < inputList.size(); i += maxSize) {
int end = Math.min(inputList.size(), i + maxSize);
List<T> partition = inputList.subList(i, end);
// 对每个分区执行数据库操作
List<R> result = operation.apply(partition);
if (result != null) {
// 根据提供的键提取器去重并收集结果
result.stream()
.collect(Collectors.toMap(distinctByKey, r -> r,
(existing, replacement) -> existing, LinkedHashMap::new))
.forEach((key, value) -> map.putIfAbsent(key, value));
}
}
return new ArrayList<>(map.values());
}
使用方式
List<Person> baseInfoList = ListUtils.executeInPartitions(personList, 1000,
partition -> personMapper.getPerson(partition), Person::getId);
标签:return,分批,partition,List,inputList,param,查询,SQL
From: https://www.cnblogs.com/live2learn/p/18400508