前言
当操作大量数据的时候往往需要分批次去处理,以减少内存和i/o的压力,比如用 mybatis-plus,添加、修改、查询大量数据时候,会造成数据库压力太大,导致服务异常,还有在执行sql 的in 方法时候,参数不能大于1000个等问题,都需要进行批量处理。下面整理一个BatchUtil 批处理工具类,很好的解决以上的问题。
工具类代码
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* 批处理工具类
*
* @version 1.0
* @since JDK1.8
* @author tarzan
* @date 2022年01月28日 16:39:50
*/
public class BatchUtil {
/**
* 批次数量
*/
public static final Integer NUMBER_BACH_PROTECT = 999;
/**
* 批量中包含有关联查询,可能因为数据过长出现数据查询的的问题,
* 这里进行分批处理
* @param list
* 需要处理的list
* @param bach
* 批量处理的函数
* @param <T>
* 元素类型
*/
public static <T> void protectBach(List<T> list, Consumer<List<T>> bach){
if (isEmpty(list)){return;}
if (list.size() > NUMBER_BACH_PROTECT) {
for (int i = 0; i < list.size(); i += NUMBER_BACH_PROTECT) {
int lastIndex = Math.min(i + NUMBER_BACH_PROTECT, list.size());
bach.accept(list.subList(i, lastIndex));
}
}else {
bach.accept(list);
}
}
/**
* 批量中包含有关联查询,可能因为数据过长出现数据查询的的问题
* 这里进行分批,合并数据处理。
* @param list
* 原数据
* @param bach
* 处理方法
* @param <T>
* 原数据类型
* @param <R>
* 处理结果类型
* @return
* 处理结果汇总
*/
public static <T, R> List<R> protectBach(List<T> list, Function<List<T>, List<R>> bach){
if (isEmpty(list)){return Collections.emptyList();}
if (list.size() > NUMBER_BACH_PROTECT) {
List<R> end = new LinkedList<>();
for (int i = 0; i < list.size(); i += NUMBER_BACH_PROTECT) {
int lastIndex = Math.min(i + NUMBER_BACH_PROTECT, list.size());
Optional.ofNullable(bach.apply(list.subList(i, lastIndex)))
.ifPresent(end::addAll);
}
return end;
}
return bach.apply(list);
}
private static <T> boolean isEmpty(Collection<T> collection) {
return collection == null || collection.isEmpty();
}
}
使用教程
比如 数据操作A和B表,A表是主表,B是子表,当批量删除A表的数据,同时删除B表关联的数据,代码如下
/**
* 方法描述: 删除
*
* @param ids
* @return {@link boolean}
*/
@Transactional(rollbackFor = Throwable.class)
public boolean delete(List<Long> ids) {
if(CollectionUtils.isEmpty(ids)){
return true;
}
removeByIds(ids);
return attributeSetService.deleteByClazz(ids);
}
/**
* 方法描述: 根据要素集删除
*
* @param setIds
* @return {@link boolean}
*/
@Transactional(rollbackFor = Throwable.class)
protected boolean delBySets(List<Long> setIds) {
LambdaQueryWrapper<FeatureClazzEntity> wrapper=new LambdaQueryWrapper();
wrapper.select(FeatureClazzEntity::getId).in(FeatureClazzEntity::getFeatureSetId,setIds);
List<Long> ids=list(wrapper).stream().map(FeatureClazzEntity::getId).collect(Collectors.toList());
BatchUtil.protectBach(ids, this::delete);
return true;
}
批量查询
比如 数据操作A和B表,A表是主表,B是子表,根据A表的数据,查出B表关联的数据,代码如下
protected List<AttributeSetEntity> selectBySets(List<Long> setIds) {
LambdaQueryWrapper<FeatureClazzEntity> wrapper=new LambdaQueryWrapper();
wrapper.select(FeatureClazzEntity::getId).in(FeatureClazzEntity::getFeatureSetId,setIds);
List<Long> ids=list(wrapper).stream().map(FeatureClazzEntity::getId).collect(Collectors.toList());
List<AttributeSetEntity> result= BatchUtil.protectBach(ids, idList->{
return attributeSetService.lambdaQuery().in(AttributeSetEntity::getClazzId,idList).list();
});
return result;
}
相关知识
Java Lambda 表达式是 Java 8 引入的一项重要特性,它为 Java 提供了一种简洁而强大的函数式编程方式。Lambda 表达式使得开发者可以以更简洁的语法实现函数式接口的实例化和使用,并在代码中更方便地处理集合、并行计算等操作。下面将详细介绍 Java Lambda 表达式的语法、特点以及在实际开发中的应用。
一、Lambda 表达式的语法:
Lambda 表达式的基本语法结构如下:
(parameters) -> expression or { statements }
其中,参数列表可以为空或包含多个参数,箭头 ->
用于分隔参数列表和 Lambda 表达式的主体部分。
-
Lambda 表达式的参数:可以是零个或多个参数,多个参数之间使用逗号进行分隔。对于无参数的情况,可以使用空括号表示。
-
Lambda 表达式的主体:可以是一个表达式(expression)或一个代码块(block)。如果主体是一个表达式,可以直接返回结果;如果主体是一个代码块,则需要使用花括号
{}
将代码块括起来,并使用return
语句显式返回结果。
二、Lambda 表达式的特点:
-
匿名函数:Lambda 表达式是一种匿名函数,不需要具名的方法来实现函数式接口的实例化。这样可以减少代码量,使得代码更加简洁和易读。
-
函数式接口:Lambda 表达式的使用场景通常是函数式接口。函数式接口是只包含一个抽象方法的接口,用于表示 Lambda 表达式所代表的行为。通过 Lambda 表达式,可以以一种更直观的方式创建函数式接口的实例。
-
类型推断:Lambda 表达式支持自动类型推断。在 Lambda 表达式中,参数的类型可以根据上下文进行推断,无需显式声明类型。
-
闭包:Lambda 表达式可以访问外部的局部变量和参数,但在 Lambda 表达式内部无法修改这些变量的值。这种特性被称为闭包,使得 Lambda 表达式具备了更大的灵活性。
三、Lambda 表达式的应用:
-
集合操作:Lambda 表达式广泛应用于集合操作中,如过滤(filter)、映射(map)、归约(reduce)等。通过 Lambda 表达式,可以以更简洁的方式对集合进行处理和转换。
-
排序和比较器:Lambda 表达式可以方便地创建比较器(Comparator),用于对集合元素进行排序。通过传递 Lambda 表达式给排序方法,可以定义不同的排序规则。
-
并行处理:Java 8 引入了并行流(Parallel Streams)的概念,可以利用多核处理器进行并行计算。通过使用 Lambda 表达式,可以更方便地编写并行处理代码,提高程序的性能。
-
GUI 编程:Lambda 表达式也可以用于简化图形用户界面(GUI)的事件处理。通过将 Lambda 表达式作为事件处理程序,可以减少匿名内部类的使用,使代码更加简洁和易读。
-
延迟执行:Lambda 表达式支持延迟执行,只有在真正需要时才会被调用。这种特性可以提高程序的效率,并避免不必要的计算和资源消耗。
总结: Java Lambda 表达式是 Java 8 引入的一项重要特性,它使得函数式编程在 Java 中变得更加便捷和强大。通过 Lambda 表达式,可以以更简洁的语法实现函数式接口的实例化和使用,并在集合操作、排序、并行处理等场景中发挥重要作用。Lambda 表达式的引入丰富了 Java 的编程模型,使得开发者能够编写更简洁、可读性更好的代码。