新闻详情

新闻详情

首页 / 资讯中心 / 详情

MyBatis 游标 Cursor 流式查询:TaoToken 统一 Key 接入与配置骨架

发布时间:2026/9/26 10:37:47来源:尧图网络
MyBatis 游标 Cursor 流式查询:TaoToken 统一 Key 接入与配置骨架
1. 大数据量导出为什么会 OOMCursor 能解决什么如果你做过报表导出、对账文件生成、离线批处理这类需求大概率遇到过这样的场景SQL 在数据库端跑得飞快4 秒就能扫出几十万行但 Java 应用这边一执行就卡死堆内存曲线直接拉满最后抛java.lang.OutOfMemoryError: Java heap space。问题不在数据库而在于 MyBatis 默认的查询行为——它会把ResultSet里的所有行一次性映射成ListT返回给你。50 万行、每行几十个字段光对象头加字段引用就是几百 MB再叠加业务侧还要做转换、拼 Excel内存直接爆掉。org.apache.ibatis.cursor.Cursor就是为这个场景准备的。它继承Iterable和Closeable查询成功后不返回集合而是返回一个迭代器应用每次从迭代器取一条结果数据库连接保持打开、结果集逐行消费。内存占用从与总行数成正比变成与单行大小成正比这是本质区别。它适合谁适合做数据导出、批量同步、大表扫描的 Java 后端同学尤其是用 MyBatis 或 MyBatis-Plus 的项目。但流式查询不是免费的午餐。连接会被独占取完之前不能在该连接上发别的查询应用必须自己负责关闭SqlSession如果中途抛异常没关连接连接池很快会被耗尽。所以工程落地的关键不是会不会写 Cursor而是配置骨架对不对、连接生命周期管没管住。这篇我会给出一套可直接复制的 MyBatis 配置、Mapper 接口、Service 消费骨架并说明怎么通过 TaoToken 统一 Key 把模型侧调用和这套数据管道串起来最后附上验证逐条读取和内存占用的操作步骤。2. TaoToken 前置统一 Key 与 API 通道准备在讲 MyBatis 配置之前先把 TaoToken 这一层说清楚因为后面验证环节要用它做模型侧的统一入口。TaoToken 是一个统一的大模型 API 接入通道你可以在一个控制台里管理多个模型的 Key用同一套鉴权方式调用不同模型省去每个模型单独申请、单独维护 Key 的麻烦。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end API 基址是 https://taotoken.net/api 。你需要做的准备动作只有三步。第一打开控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 注册并登录。第二进入 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建一个 Key复制保存它只显示一次。第三如果你打算在编辑器或 Agent 里用可以看接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的调用示例。注意Key 属于敏感凭证不要写进代码仓库用环境变量或配置中心注入。本文所有配置片段里的 Key 都用占位符sk-xxxx表示。为什么数据管道项目要接 TaoToken因为很多导出任务后面会跟一步用模型做字段清洗、摘要、分类的处理。如果每个模型一个 Key、一套 SDK维护成本很高。统一 Key 之后你的settings.json或config.toml里只放一份凭证切换模型只改模型名不改鉴权逻辑。下面第 3 节会给出这两份配置骨架。3. 可复制配置MyBatis Cursor settings.json/config.toml 骨架3.1 MyBatis 核心配置流式查询要生效fetchSize必须设置。MySQL 系数据库用Integer.MIN_VALUE触发逐行流式读取其他数据库按驱动要求设置正数。最稳妥的方式是在 Mapper 方法上用Options注解而不是全局配置避免影响其他查询。import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.cursor.Cursor; import org.apache.ibatis.annotations.Mapper; Mapper public interface NetworkOutputTableMapper { // fetchSize Integer.MIN_VALUE 触发 MySQL 流式读取 Options(fetchSize Integer.MIN_VALUE) CursorNetworkOutputTableVO streamAll(Param(vo) ExportExcelVO vo); Integer getTotal(); }对应的 XML 映射文件保持普通写法即可不需要特殊标签select idstreamAll resultTypecom.example.vo.NetworkOutputTableVO SELECT id, user_name, amount, create_time FROM network_output_table WHERE create_time gt; #{vo.startTime} ORDER BY id /selectSqlSessionFactory的配置里ExecutorType用默认的SIMPLE就行不要用BATCH批处理模式对流式游标支持不好。数据源连接池建议把maxPoolSize调大一点因为每个流式查询独占一个连接并发导出任务多的时候连接需求会上升。spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 mybatis: mapper-locations: classpath:mapper/*.xml configuration: default-fetch-size: 100 default-statement-timeout: 3003.2 settings.json 骨架编辑器/Agent 场景如果你在支持settings.json的编辑器里配置模型接入骨架如下。把baseUrl指向 TaoToken 的 API 地址apiKey用环境变量引用{ models: { provider: openai-compatible, baseUrl: https://taotoken.net/api, apiKey: ${TAOTOKEN_API_KEY}, model: claude-sonnet-4-5, timeout: 120000 }, features: { streaming: true, maxTokens: 8192 } }3.3 config.toml 骨架CLI/服务端场景用 TOML 配置的项目可以这样写结构更清晰[llm] base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} model claude-sonnet-4-5 timeout_seconds 120 [llm.stream] enabled true chunk_size 512 [export] batch_size 10000 fetch_size -2147483648fetch_size -2147483648就是Integer.MIN_VALUE的十进制值放在配置里方便统一管理。batch_size是业务侧每积累多少条处理一次和游标读取解耦。4. 验证请求逐条读取与内存占用实测4.1 Service 消费骨架下面这段是可直接运行的消费逻辑重点看try-with-resources和手动SqlSession管理。注意Cursor必须在SqlSession关闭前消费完否则连接不会释放。import org.apache.ibatis.cursor.Cursor; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; Slf4j Service public class StreamExportService { private final SqlSessionFactory sqlSessionFactory; public StreamExportService(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory sqlSessionFactory; } public void export(ExportExcelVO vo) { long start System.currentTimeMillis(); int batchSize 10000; int totalRead 0; int batchNo 0; try (SqlSession session sqlSessionFactory.openSession()) { NetworkOutputTableMapper mapper session.getMapper(NetworkOutputTableMapper.class); ListNetworkOutputTableVO buffer new ArrayList(batchSize); try (CursorNetworkOutputTableVO cursor mapper.streamAll(vo)) { for (NetworkOutputTableVO row : cursor) { buffer.add(row); totalRead; if (buffer.size() batchSize) { batchNo; processBatch(buffer, batchNo); buffer.clear(); } } if (!buffer.isEmpty()) { batchNo; processBatch(buffer, batchNo); buffer.clear(); } log.info(消费完毕, isConsumed{}, currentIndex{}, cursor.isConsumed(), cursor.getCurrentIndex()); } session.commit(); } catch (Exception e) { log.error(流式导出失败, e); throw new RuntimeException(e); } log.info(总读取 {} 条, 耗时 {} ms, totalRead, System.currentTimeMillis() - start); } private void processBatch(ListNetworkOutputTableVO batch, int batchNo) { // 这里做写文件、调模型、入库等操作 log.info(处理第 {} 批, 本批 {} 条, batchNo, batch.size()); } }4.2 内存占用验证步骤想确认流式真的生效不要只看代码要实测。启动应用时加上 JVM 参数限制堆大小制造如果全量加载必 OOM的环境java -Xmx256m -Xms256m -jar your-app.jar然后在导出接口里打日志每处理 1 万条打印一次Runtime已用内存Runtime rt Runtime.getRuntime(); long usedMb (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024; log.info(batch {} done, used heap {} MB, batchNo, usedMb);实测下来50 万行数据在 256MB 堆下全量加载会在几秒内 OOM而流式读取的已用堆内存会稳定在 80–150MB 之间波动不会随总行数线性增长。这就是判断流式是否真正生效的硬指标。4.3 模型侧验证请求数据管道跑通后如果你要接模型做后续处理先用一条最小请求验证 TaoToken 通道是否通。用 curl 测试curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 用一句话说明流式查询的好处}], stream: false }返回 200 且choices[0].message.content有内容说明 Key 和通道都正常。想直接在网页里试模型可以打开模型对话 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 不用写代码就能验证。5. 本篇常见错排查5.1 Cursor 返回空或直接抛异常最常见的原因是fetchSize没生效。检查三点Options(fetchSize Integer.MIN_VALUE)是否加在 Mapper 方法上数据库驱动版本是否支持流式MySQL Connector/J 5.1.30 才稳定支持是否用了ExecutorType.BATCH。另外如果 XML 里用了foreach拼超长 IN 条件某些驱动会退化成全量加载建议改成 JOIN 或临时表。5.2 连接池耗尽 / 连接不释放流式查询独占连接如果消费逻辑里又去调用了同一个数据源的其他查询会死锁或超时。典型报错是HikariPool-1 - Connection is not available, request timed out。解决办法流式查询用独立的SqlSession消费过程中不要在该 session 上发别的 SQL确保try-with-resources包住Cursor和SqlSession异常分支也要能走到close()。5.3 事务提交后数据不一致Cursor消费期间连接处于打开状态如果中途rollback已消费的数据不会回滚但数据库端可能已经读了部分行。对于只读导出场景建议不开事务或只读事务对于读一批写一批的场景把写操作放到独立事务里不要和游标共享 session。5.4 TaoToken 请求 401 或超时401 通常是 Key 没读到环境变量检查${TAOTOKEN_API_KEY}是否真的注入了可以echo $TAOTOKEN_API_KEY确认。超时的话把timeout调到 120000ms 以上长文本处理容易超过默认 30s。如果是在编辑器里配置确认baseUrl结尾没有多余的/v1TaoToken 的基址是https://taotoken.net/api具体路径按文档拼接。5.5 内存还是涨如果已用堆内存随行数缓慢上涨检查buffer有没有在每批处理后真正clear()以及NetworkOutputTableVO里有没有大字段比如byte[]、长文本被缓存。另外Cursor迭代过程中 MyBatis 会持有ResultSet的引用这是正常的只要不把每行对象都塞进一个全局 List 就行。6. 长期编码与 Agent 场景的接入建议如果你的导出管道后面要长期接模型做字段清洗、摘要、分类建议把模型调用也纳入统一管理而不是每次临时拼 Key。TaoToken 的 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 适合长期编码和 Agent 场景一份配置覆盖多个模型切换只改模型名。接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里有完整的参数说明和错误码对照排障时对着查比猜快得多。回到 MyBatis 这边最后给你一个实用技巧把batchSize和fetchSize做成配置项不同环境用不同值。开发环境batchSize1000方便调试生产环境batchSize10000减少 IO 次数。游标读取本身不慢慢的是每批处理里的写文件或网络调用所以批大小要按下游处理能力来定而不是拍脑袋。我试过把batchSize从 10000 调到 50000结果单批处理时间过长导致连接被数据库端wait_timeout掐断反而更麻烦。稳定压倒一切。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Deskcomm CRM落地实战:从客户数据统一到自动化流程优化 2026/9/26 11:30:54

Deskcomm CRM落地实战:从客户数据统一到自动化流程优化

一个听起来像“桌面通信客户管理”的CRM名字,其实暗含了一条很关键的产品思路:把企业和客户之间的每一次接触沉淀成可管理、可追踪、可复用的数据资产。我最早接触DeskcommCRM,是在团队同时维护销售线索、售后工单、客服消息三个系统&#xf…

阅读更多 →
从AlexNet到ViT:PyTorch统一训练模板与模型部署实践 2026/9/26 11:30:47

从AlexNet到ViT:PyTorch统一训练模板与模型部署实践

1. 背景与核心概念如果现在要评选过去十年影响最深远的深度学习模型,卷积神经网络(Convolutional Neural Network,CNN)一定是最有竞争力的候选之一。从 2012 年 AlexNet 在 ImageNet 大赛上一举夺冠开始,CNN 逐步成为图…

阅读更多 →
PyTorch统一训练模板:CNN与ViT图像分类模型工程化实战 2026/9/26 11:30:47

PyTorch统一训练模板:CNN与ViT图像分类模型工程化实战

学深度学习图像分类,最容易遇到的一个坑不是模型看不懂,而是每个模型对应一套独立的训练代码。上周还在用 torchvision 读 AlexNet,这周导师让换成 ResNet,网上找到的代码数据预处理是一套写法,训练循环又是另一种封装…

阅读更多 →
一个模板搞定四类视觉模型:CNN与ViT的统一训练部署 2026/9/26 11:30:47

一个模板搞定四类视觉模型:CNN与ViT的统一训练部署

这次我们来看一份能直接套用的深度学习训练模板。主题是 CNN,但又不只是 CNN——用同一套 Python 代码,把 AlexNet、VGG、ResNet、ViT 四类主流视觉模型的训练、验证、导出和部署全流程串起来。很多新手刚接触图像分类时,问题往往不是“模型不…

阅读更多 →
无线网卡选购指南:USB、PCIe、M.2接口与WiFi6/7性能横评 2026/9/26 11:30:47

无线网卡选购指南:USB、PCIe、M.2接口与WiFi6/7性能横评

1. 无线网卡选购的核心逻辑与接口选型1.1 为什么接口形态决定了你的使用体验很多人挑无线网卡的时候,第一反应是看天线数量、看速率标称、看品牌,但真正决定你这块网卡能不能用得舒服、能不能跑满速率的,其实是接口形态。USB、PCIe、M.2这三种…

阅读更多 →
SSVEP脑机接口代码实战:从刺激范式到CCA/FBCCA识别与避坑指南 2026/9/26 11:30:47

SSVEP脑机接口代码实战:从刺激范式到CCA/FBCCA识别与避坑指南

简介:这是一套面向生物医学工程与脑机接口初学者的 SSVEP(稳态视觉诱发电位)研究代码包,覆盖从 EEG 数据读取、预处理、频域分析到特征提取与分类识别的完整流程。包内以 MATLAB 的 m 文件为主,共 34 个文件&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉