From a58caadbaacaa04b38a3c14563addbe7e24b2ff5 Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Sun, 3 Aug 2025 15:42:16 +0800 Subject: [PATCH 1/2] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9EResultHandler?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/handler/BatchResultHandler.java | 101 ++++++++++++++++++ .../mybatis/handler/FilterResultHandler.java | 64 +++++++++++ .../mybatis/handler/SimpleResultHandler.java | 48 +++++++++ 3 files changed, 213 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java new file mode 100644 index 000000000..bd505a038 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java @@ -0,0 +1,101 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.collection.CollUtil; +import org.apache.ibatis.session.ResultContext; +import org.apache.ibatis.session.ResultHandler; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * 批量结果处理器 + * + *

将查询结果按指定批量大小缓存, + * 达到批量大小时调用批量消费函数进行批量处理,避免一次性加载全部数据导致内存压力过大 + * + *

适用于导出Excel、批量写库、定时上报等需要批量操作场景, + * 能有效降低内存使用并提升处理性能 + * + *

使用须知:
+ * 1. 构造时传入非空的批量消费函数和合法的批量大小(>0)
+ * 2. 结果回调时自动缓存并批量触发消费函数
+ * 3. 查询完成后务必调用 {@link #flush()},处理剩余不足批量的数据,避免数据遗漏 + * + * @param 查询结果类型 + * @author AprilWind + */ +public class BatchResultHandler implements ResultHandler { + + /** + * 批量数据消费函数 + * + *

注意:长时间的批量处理操作(如写Excel、写数据库或调用远程接口)可能导致数据库连接超时或断开, + * 以及MyBatis查询线程阻塞,影响系统性能和稳定性。 + * + *

因此推荐: + *

+ * + *

这样能有效保障系统的高性能和稳定运行 + */ + private final Consumer> batchConsumer; + + /** + * 批量大小,必须大于0 + */ + private final int batchSize; + + /** + * 当前缓存数据 + */ + private final List buffer; + + /** + * 构造批量结果处理器 + * + * @param batchConsumer 批量消费函数,不能为null + * @param batchSize 批量大小,必须大于0 + * @throws NullPointerException batchConsumer为null时抛出 + * @throws IllegalArgumentException batchSize小于等于0时抛出 + */ + public BatchResultHandler(Consumer> batchConsumer, int batchSize) { + if (batchConsumer == null) { + throw new NullPointerException("batchConsumer不能为null"); + } + if (batchSize <= 0) { + throw new IllegalArgumentException("batchSize必须大于0"); + } + this.batchConsumer = batchConsumer; + this.batchSize = batchSize; + this.buffer = new ArrayList<>(batchSize); + } + + /** + * MyBatis 查询结果回调,缓存单条结果, + * 达到批量大小时触发批量消费函数处理缓存数据 + * + * @param context 查询结果上下文,包含单条结果 + */ + @Override + public void handleResult(ResultContext context) { + buffer.add(context.getResultObject()); + if (buffer.size() >= batchSize) { + flush(); + } + } + + /** + * 刷新缓存,触发批量消费函数处理剩余数据, + * 通常查询结束后调用,确保所有数据均被处理 + */ + public void flush() { + if (CollUtil.isNotEmpty(buffer)) { + batchConsumer.accept(new ArrayList<>(buffer)); + buffer.clear(); + } + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java new file mode 100644 index 000000000..6496458d6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java @@ -0,0 +1,64 @@ +package org.dromara.common.mybatis.handler; + +import org.apache.ibatis.session.ResultContext; +import org.apache.ibatis.session.ResultHandler; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * 过滤处理器 + *

+ * 通过传入的过滤条件({@link Predicate})筛选查询结果, + * 仅对满足条件的结果调用消费函数进行处理 + *

+ * 适用于需要对查询结果做条件过滤再处理的场景 + * 避免无用数据进入后续处理逻辑,提高效率 + * + * @param 查询结果的数据类型 + * @author AprilWind + */ +public class FilterResultHandler implements ResultHandler { + + /** + * 过滤条件,用于判断是否处理该条结果 + */ + private final Predicate filter; + + /** + * 处理满足过滤条件的结果的消费函数 + */ + private final Consumer consumer; + + /** + * 构造过滤处理器 + * + * @param filter 过滤条件 + * @param consumer 满足过滤条件时的处理函数 + * @throws NullPointerException 如果 filter 或 consumer 为 null + */ + public FilterResultHandler(Predicate filter, Consumer consumer) { + if (filter == null) { + throw new NullPointerException("过滤条件,不能为空"); + } + if (consumer == null) { + throw new NullPointerException("处理函数,不能为空"); + } + this.filter = filter; + this.consumer = consumer; + } + + /** + * 查询结果回调,先用过滤条件判断是否处理 + * 满足条件则调用消费函数,否则忽略该条结果 + * + * @param context 查询结果上下文,包含单条结果 + */ + @Override + public void handleResult(ResultContext context) { + T result = context.getResultObject(); + if (filter.test(result)) { + consumer.accept(result); + } + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java new file mode 100644 index 000000000..c5950da1a --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java @@ -0,0 +1,48 @@ +package org.dromara.common.mybatis.handler; + +import org.apache.ibatis.session.ResultContext; +import org.apache.ibatis.session.ResultHandler; + +import java.util.function.Consumer; + +/** + * 单条处理处理器 + * + *

适用于无需缓存或批量处理,直接对结果逐条消费的场景 + * 逻辑简单直接,实时处理每条数据 + * + * @param 查询结果的数据类型 + * @author AprilWind + */ +public class SimpleResultHandler implements ResultHandler { + + /** + * 消费单条查询结果的函数 + */ + private final Consumer consumer; + + /** + * 构造 SimpleResultHandler 实例 + * + * @param consumer 处理单条查询结果的消费函数,不能为空 + * @throws NullPointerException 如果 consumer 为 null 抛出 + */ + public SimpleResultHandler(Consumer consumer) { + if (consumer == null) { + throw new NullPointerException("consumer不能为null"); + } + this.consumer = consumer; + } + + /** + * MyBatis 查询结果回调方法, + * 每接收到一条查询结果即调用消费函数进行处理 + * + * @param context 查询结果上下文,包含当前单条结果对象 + */ + @Override + public void handleResult(ResultContext context) { + T result = context.getResultObject(); + consumer.accept(result); + } +} -- Gitee From 3db7f8ce74ebb8dd447388628ef1c59be340785c Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Sun, 3 Aug 2025 16:22:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9E=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=99=A8=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mybatis/core/mapper/BaseMapperPlus.java | 33 +++++++++++++++++++ .../mybatis/handler/BatchResultHandler.java | 8 ----- .../mybatis/handler/FilterResultHandler.java | 7 ---- .../mybatis/handler/SimpleResultHandler.java | 4 --- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java index 0d777f4e0..9785b0832 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java @@ -15,12 +15,15 @@ import org.apache.ibatis.logging.Log; import org.apache.ibatis.logging.LogFactory; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.mybatis.handler.FilterResultHandler; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.function.Predicate; /** * 自定义 Mapper 接口, 实现 自定义扩展 @@ -355,4 +358,34 @@ public interface BaseMapperPlus extends BaseMapper { return StreamUtils.toList(this.selectObjs(wrapper), mapper); } + /** + * 根据查询条件和过滤条件查询数据,并将结果转换为指定的VO类型列表 + * + * @param wrapper 查询条件Wrapper + * @param filter 结果过滤条件 + * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回 + */ + default List selectFilterVoList(Wrapper wrapper, Predicate filter) { + return this.selectFilterVoList(wrapper, filter, this.currentVoClass()); + } + + /** + * 根据查询条件和过滤条件查询数据,并将结果转换为指定的VO类型列表 + * + * @param wrapper 查询条件Wrapper + * @param filter 结果过滤条件 + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回 + */ + default List selectFilterVoList(Wrapper wrapper, Predicate filter, Class voClass) { + List list = new ArrayList<>(); + // 使用过滤处理器过滤数据,并将符合条件的结果加入 list + this.selectList(wrapper, new FilterResultHandler<>(filter, list::add)); + + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java index bd505a038..cfa7a6233 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/BatchResultHandler.java @@ -59,16 +59,8 @@ public class BatchResultHandler implements ResultHandler { * * @param batchConsumer 批量消费函数,不能为null * @param batchSize 批量大小,必须大于0 - * @throws NullPointerException batchConsumer为null时抛出 - * @throws IllegalArgumentException batchSize小于等于0时抛出 */ public BatchResultHandler(Consumer> batchConsumer, int batchSize) { - if (batchConsumer == null) { - throw new NullPointerException("batchConsumer不能为null"); - } - if (batchSize <= 0) { - throw new IllegalArgumentException("batchSize必须大于0"); - } this.batchConsumer = batchConsumer; this.batchSize = batchSize; this.buffer = new ArrayList<>(batchSize); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java index 6496458d6..0c9096700 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/FilterResultHandler.java @@ -35,15 +35,8 @@ public class FilterResultHandler implements ResultHandler { * * @param filter 过滤条件 * @param consumer 满足过滤条件时的处理函数 - * @throws NullPointerException 如果 filter 或 consumer 为 null */ public FilterResultHandler(Predicate filter, Consumer consumer) { - if (filter == null) { - throw new NullPointerException("过滤条件,不能为空"); - } - if (consumer == null) { - throw new NullPointerException("处理函数,不能为空"); - } this.filter = filter; this.consumer = consumer; } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java index c5950da1a..13dc06010 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/SimpleResultHandler.java @@ -25,12 +25,8 @@ public class SimpleResultHandler implements ResultHandler { * 构造 SimpleResultHandler 实例 * * @param consumer 处理单条查询结果的消费函数,不能为空 - * @throws NullPointerException 如果 consumer 为 null 抛出 */ public SimpleResultHandler(Consumer consumer) { - if (consumer == null) { - throw new NullPointerException("consumer不能为null"); - } this.consumer = consumer; } -- Gitee