流式查询:逐条返回

FLUX.1-dev

FLUX.1-dev

图片生成
FLUX

FLUX.1-dev 是一个由 Black Forest Labs 创立的开源 AI 图像生成模型版本,它以其高质量和类似照片的真实感而闻名,并且比其他模型更有效率

MyBatis Cursor + Reactor Flux.create

        MyBatis 提供了 Cursor 接口,它本质上是对 JDBC ResultSet 的一个包装。当使用 Cursor 时,MyBatis 不会一次性将所有结果加载到内存中,而是逐行从数据库读取。我们可以将这个逐行的、阻塞的迭代过程,转换成一个非阻塞的、异步的 Flux 数据流。

        数据流如下:MySQL -> JDBC ResultSet (流式) -> MyBatis Cursor -> (在专用线程中迭代) -> Flux.create -> Spring WebFlux Controller -> Client

实现步骤与代码示例

第一步:MyBatis Mapper 层配置游标查询

在你的 Mapper 接口中,定义一个返回 Cursor 的方法。

import org.apache.ibatis.cursor.Cursor;

@Mapper
public interface HugeDataMapper {
    // 方法返回类型必须是 Cursor
    Cursor<YourDataModel> streamAllData();
}

对应的 XML 映射文件(如果使用XML):

<select id="streamAllData" resultType="YourDataModel">
    SELECT * FROM your_huge_table
    <!-- 可以添加 WHERE 条件等 -->
</select>

关键点: 仅仅是定义返回 Cursor,MyBatis 就会使用流式方式执行查询。

第二步:Service 层封装为 Flux

        这是最关键的一步。我们需要在一个专门的、有边界的线程池(Schedulers.boundedElastic())中执行这个阻塞的游标遍历操作,并将每一行数据通过 Flux.create 的 sink 发射出去。

import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class StreamService {

    private final HugeDataMapper hugeDataMapper; // 你的 MyBatis Mapper

    public Flux<YourDataModel> streamHugeData() {
        return Flux.create(sink -> {
            // 这段代码将在弹性线程池中执行,不会阻塞WebFlux的事件循环线程
            try (Cursor<YourDataModel> cursor = hugeDataMapper.streamAllData()) {
                cursor.forEach(sink::next); // 逐行遍历,并通过sink发射数据
                sink.complete(); // 遍历完成,发出完成信号
            } catch (Exception e) {
                sink.error(e); // 发生异常,发出错误信号
            }
        }).subscribeOn(Schedulers.boundedElastic()); // 指定上述操作所在的线程池
    }
}

代码解释:
        (1) Flux.create: 创建一个 Flux,我们可以完全控制如何向其中发射数据。
        (2) subscribeOn(Schedulers.boundedElastic()): 这是至关重要的一步。它将整个阻塞的游标遍历操作(包括数据库查询)转移到一个专门的、大小受限的弹性线程池中执行。这保护了 WebFlux 用于处理高并发请求的有限的事件循环线程(EventLoop Thread),防止它们被阻塞操作拖垮。在
        (3) create 的回调中:
        使用 forEach 逐行遍历,每拿到一行数据,就调用 sink.next(data) 将其发射出去。
        遍历完成后调用 sink.complete()。
        用 try-with-resources 语句确保 Cursor 和底层的 ResultSet、Connection 会被正确关闭。

第三步:Controller 层暴露流式端点

在 Controller 中,注入 Service 并返回这个 Flux。

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class StreamingController {

    private final StreamService streamService;

    @GetMapping(value = "/stream/data", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<YourDataModel> streamData() {
        return streamService.streamHugeData();
    }
}

关键点:

        (1) produces = MediaType.TEXT_EVENT_STREAM_VALUE: 这声明了该端点使用 Server-Sent Events (SSE) 协议进行响应。这是最常用的流式传输协议,前端可以直接用 EventSource API 来消费。

        (2) 你也可以使用 MediaType.APPLICATION_NDJSON_VALUE,它会以换行符分隔的 JSON 格式返回数据。

第四步:配置

1. MySQL JDBC 连接参数

        为了确保 MySQL JDBC 驱动真正使用流式传输,必须在数据库连接 URL 中配置以下参数:properties

# application.properties

spring.datasource.url=jdbc:mysql://your-host:3306/your-db?
    useCursorFetch=true& # 启用游标抓取
    defaultFetchSize=-2147483648&# 设置默认抓取大小为 Integer.MIN_VALUE,这是驱动层流式传输的关键
    characterEncoding=UTF-8&
    serverTimezone=Asia/Shanghai

defaultFetchSize=-2147483648 是驱动识别为“流式模式”的魔法值。useCursorFetch=true 与之配合使用。

2. 连接池配置 (重要!)

        必须确保连接池不会干扰流式查询。 常见的连接池(如 HikariCP)会在连接归还时关闭任何打开的 ResultSet,这会立即中断你的流。

解决方案:使用 Spring 事务管理, 在 @Transactional 注解的方法中执行游标查询,这样可以保证在整个流式读取完成之前,连接不会被归还。你可以将 @Transactional 注解加在 Mapper 方法上或 Service 方法上。

@Service
public class StreamService {
    ...

    @Transactional // 添加事务注解,保持连接直到整个流处理完毕
    public Flux<YourDataModel> streamHugeData() {
        return Flux.create(sink -> {
            try (Cursor<YourDataModel> cursor = hugeDataMapper.streamAllData()) {
                cursor.forEach(sink::next);
                sink.complete();
            } catch (Exception e) {
                sink.error(e);
            }
        }).subscribeOn(Schedulers.boundedElastic());
    }
}

您可能感兴趣的与本文相关的镜像

FLUX.1-dev

FLUX.1-dev

图片生成
FLUX

FLUX.1-dev 是一个由 Black Forest Labs 创立的开源 AI 图像生成模型版本,它以其高质量和类似照片的真实感而闻名,并且比其他模型更有效率

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值