mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-18 17:38:48 +08:00
Pre Merge pull request !736 from AprilWind/dev
This commit is contained in:
commit
0bc9ed7677
@ -15,12 +15,15 @@ import org.apache.ibatis.logging.Log;
|
|||||||
import org.apache.ibatis.logging.LogFactory;
|
import org.apache.ibatis.logging.LogFactory;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.mybatis.handler.FilterResultHandler;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义 Mapper 接口, 实现 自定义扩展
|
* 自定义 Mapper 接口, 实现 自定义扩展
|
||||||
@ -355,4 +358,34 @@ public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
|
|||||||
return StreamUtils.toList(this.selectObjs(wrapper), mapper);
|
return StreamUtils.toList(this.selectObjs(wrapper), mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据查询条件和过滤条件查询数据,并将结果转换为指定的VO类型列表
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param filter 结果过滤条件
|
||||||
|
* @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回
|
||||||
|
*/
|
||||||
|
default List<V> selectFilterVoList(Wrapper<T> wrapper, Predicate<T> filter) {
|
||||||
|
return this.selectFilterVoList(wrapper, filter, this.currentVoClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据查询条件和过滤条件查询数据,并将结果转换为指定的VO类型列表
|
||||||
|
*
|
||||||
|
* @param wrapper 查询条件Wrapper
|
||||||
|
* @param filter 结果过滤条件
|
||||||
|
* @param voClass 要转换的VO类的Class对象
|
||||||
|
* @param <C> VO类的类型
|
||||||
|
* @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回
|
||||||
|
*/
|
||||||
|
default <C> List<C> selectFilterVoList(Wrapper<T> wrapper, Predicate<T> filter, Class<C> voClass) {
|
||||||
|
List<T> list = new ArrayList<>();
|
||||||
|
// 使用过滤处理器过滤数据,并将符合条件的结果加入 list
|
||||||
|
this.selectList(wrapper, new FilterResultHandler<>(filter, list::add));
|
||||||
|
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return CollUtil.newArrayList();
|
||||||
|
}
|
||||||
|
return MapstructUtils.convert(list, voClass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量结果处理器
|
||||||
|
*
|
||||||
|
* <p>将查询结果按指定批量大小缓存,
|
||||||
|
* 达到批量大小时调用批量消费函数进行批量处理,避免一次性加载全部数据导致内存压力过大
|
||||||
|
*
|
||||||
|
* <p>适用于导出Excel、批量写库、定时上报等需要批量操作场景,
|
||||||
|
* 能有效降低内存使用并提升处理性能
|
||||||
|
*
|
||||||
|
* <p><b>使用须知:</b><br>
|
||||||
|
* 1. 构造时传入非空的批量消费函数和合法的批量大小(>0)<br>
|
||||||
|
* 2. 结果回调时自动缓存并批量触发消费函数<br>
|
||||||
|
* 3. 查询完成后务必调用 {@link #flush()},处理剩余不足批量的数据,避免数据遗漏
|
||||||
|
*
|
||||||
|
* @param <T> 查询结果类型
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
public class BatchResultHandler<T> implements ResultHandler<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量数据消费函数
|
||||||
|
*
|
||||||
|
* <p>注意:长时间的批量处理操作(如写Excel、写数据库或调用远程接口)可能导致数据库连接超时或断开,
|
||||||
|
* 以及MyBatis查询线程阻塞,影响系统性能和稳定性。
|
||||||
|
*
|
||||||
|
* <p>因此推荐:
|
||||||
|
* <ul>
|
||||||
|
* <li>结合合适的批量大小和限速策略,避免瞬时过载</li>
|
||||||
|
* <li>采用异步写入机制,将批量处理操作与MyBatis查询线程解耦,减少阻塞</li>
|
||||||
|
* <li>合理拆分查询任务,避免长时间持有数据库连接</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>这样能有效保障系统的高性能和稳定运行
|
||||||
|
*/
|
||||||
|
private final Consumer<List<T>> batchConsumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量大小,必须大于0
|
||||||
|
*/
|
||||||
|
private final int batchSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前缓存数据
|
||||||
|
*/
|
||||||
|
private final List<T> buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造批量结果处理器
|
||||||
|
*
|
||||||
|
* @param batchConsumer 批量消费函数,不能为null
|
||||||
|
* @param batchSize 批量大小,必须大于0
|
||||||
|
*/
|
||||||
|
public BatchResultHandler(Consumer<List<T>> batchConsumer, int batchSize) {
|
||||||
|
this.batchConsumer = batchConsumer;
|
||||||
|
this.batchSize = batchSize;
|
||||||
|
this.buffer = new ArrayList<>(batchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis 查询结果回调,缓存单条结果,
|
||||||
|
* 达到批量大小时触发批量消费函数处理缓存数据
|
||||||
|
*
|
||||||
|
* @param context 查询结果上下文,包含单条结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handleResult(ResultContext<? extends T> context) {
|
||||||
|
buffer.add(context.getResultObject());
|
||||||
|
if (buffer.size() >= batchSize) {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新缓存,触发批量消费函数处理剩余数据,
|
||||||
|
* 通常查询结束后调用,确保所有数据均被处理
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
if (CollUtil.isNotEmpty(buffer)) {
|
||||||
|
batchConsumer.accept(new ArrayList<>(buffer));
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤处理器
|
||||||
|
* <p>
|
||||||
|
* 通过传入的过滤条件({@link Predicate})筛选查询结果,
|
||||||
|
* 仅对满足条件的结果调用消费函数进行处理
|
||||||
|
* <p>
|
||||||
|
* 适用于需要对查询结果做条件过滤再处理的场景
|
||||||
|
* 避免无用数据进入后续处理逻辑,提高效率
|
||||||
|
*
|
||||||
|
* @param <T> 查询结果的数据类型
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
public class FilterResultHandler<T> implements ResultHandler<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤条件,用于判断是否处理该条结果
|
||||||
|
*/
|
||||||
|
private final Predicate<T> filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理满足过滤条件的结果的消费函数
|
||||||
|
*/
|
||||||
|
private final Consumer<T> consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造过滤处理器
|
||||||
|
*
|
||||||
|
* @param filter 过滤条件
|
||||||
|
* @param consumer 满足过滤条件时的处理函数
|
||||||
|
*/
|
||||||
|
public FilterResultHandler(Predicate<T> filter, Consumer<T> consumer) {
|
||||||
|
this.filter = filter;
|
||||||
|
this.consumer = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询结果回调,先用过滤条件判断是否处理
|
||||||
|
* 满足条件则调用消费函数,否则忽略该条结果
|
||||||
|
*
|
||||||
|
* @param context 查询结果上下文,包含单条结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handleResult(ResultContext<? extends T> context) {
|
||||||
|
T result = context.getResultObject();
|
||||||
|
if (filter.test(result)) {
|
||||||
|
consumer.accept(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package org.dromara.common.mybatis.handler;
|
||||||
|
|
||||||
|
import org.apache.ibatis.session.ResultContext;
|
||||||
|
import org.apache.ibatis.session.ResultHandler;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单条处理处理器
|
||||||
|
*
|
||||||
|
* <p>适用于无需缓存或批量处理,直接对结果逐条消费的场景
|
||||||
|
* 逻辑简单直接,实时处理每条数据
|
||||||
|
*
|
||||||
|
* @param <T> 查询结果的数据类型
|
||||||
|
* @author AprilWind
|
||||||
|
*/
|
||||||
|
public class SimpleResultHandler<T> implements ResultHandler<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费单条查询结果的函数
|
||||||
|
*/
|
||||||
|
private final Consumer<T> consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造 SimpleResultHandler 实例
|
||||||
|
*
|
||||||
|
* @param consumer 处理单条查询结果的消费函数,不能为空
|
||||||
|
*/
|
||||||
|
public SimpleResultHandler(Consumer<T> consumer) {
|
||||||
|
this.consumer = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis 查询结果回调方法,
|
||||||
|
* 每接收到一条查询结果即调用消费函数进行处理
|
||||||
|
*
|
||||||
|
* @param context 查询结果上下文,包含当前单条结果对象
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handleResult(ResultContext<? extends T> context) {
|
||||||
|
T result = context.getResultObject();
|
||||||
|
consumer.accept(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user