流式查询实战:从原理到代码,彻底解决大数据量导出OOM

发布时间:2026/10/8 16:06:48

流式查询实战:从原理到代码,彻底解决大数据量导出OOM 如果你在项目里处理过百万级数据的导出一定不会对下面这个报错陌生java.lang.OutOfMemoryError: Java heap space。尤其是在做报表导出、数据对账、定时任务批量拉取这些场景里数据量一旦上去JVM 内存就像个漏水的桶怎么调-Xmx都不够用。很多人第一反应是“把堆内存调大”但调大只能延缓崩溃并不能解决问题——真正该做的是从查询方式上切断 OOM 的根源。这个话题的核心就落在两个关键词上流式查询和OOM。流式查询不是说 SQL 写得有多花哨而是在 JDBC 层面换一种数据读取模式让数据库游标一行一行地把数据吐给应用而不是一次性把几百万行全部塞进内存。配合得当的话哪怕导出五百万行数据应用内存占用也能稳定在几十 MB 的级别。这篇文章会从内存溢出的根源讲起把流式查询的原理、代码实现、参数配置和真实项目里的坑都过一遍适合正在被大数据量导出折磨的后端开发、报表开发和技术负责人参考。1. 内容整体设计与思路拆解1.1 为什么“一次性查出来再导出”一定会出问题先看一个最常见的实现ListMapString, Object list jdbcTemplate.queryForList(sql)然后拿着这个 list 去生成 Excel。在数据量只有几万条的时候这个写法一点问题都没有但一旦到几十万、上百万事情就开始失控。拆开看 JVM 内存的使用情况。假设一张订单表有 50 个字段平均一个字段 20 个字符一行数据大约 1KB。100 万行就是 1GB 左右的原始数据但 Java 对象是有开销的——每个 String 对象有 24 字节的对象头Map 和 List 还有自己的容器开销算下来 100 万行订单数据在堆里轻轻松松吃掉 2GB 到 3GB。如果一次查 500 万行-Xmx4g都不一定扛得住。更麻烦的是这个内存峰值发生在导出初期。JVM 收到全部数据之后才开始写 Excel也就是说从查询结束到第一个字节写入文件内存已经被塞满过一次了。再加上 ConcurrentHashMap 扩容、GC 复制存活对象、Excel 工具自身的缓冲整个导出过程的内存水位会反复冲高几乎必然触发 Full GC严重的时候直接抛 OOM。1.2 流式查询的核心思路把“一次全量”改成“按批消费”流式查询要解决的本质问题是消除结果集在应用层的全量驻留。在传统查询模式下JDBC 驱动会等 SQL 执行完后把完整结果集从数据库传输到客户端并全部物化成 Java 对象。在流式模式下JDBC 驱动只从数据库读取当前游标位置的一行数据应用处理完这一行后再请求下一行。数据不是一次性“倾倒”进内存而是像水流一样源源不断地“流”进来每处理一条就释放一条。这样做的直接收益是内存占用从“数据总量大小”变成“单行数据大小”两者之间差了若干个数量级。比如单行数据只有 1KB那不管查多少行应用内存里同时存在的只有这 1KB再加上 JDBC 驱动内部缓冲区的少量内存整体开销完全可以忽略。但这里有一个关键误区——流式查询不是一种独立的 API而是一组 JDBC 参数和数据库行为的组合。不同数据库驱动对流式的支持方式完全不一样配置错了你以为自己在用流式查询实际底层还是全量加载OOM 照样来。这也是为什么很多人在网上抄了一段setFetchSize()代码却一点效果都没有的原因。2. 核心方案选型两种主流的流式实现路线2.1 方案一JDBC 原生游标式读取第一种思路是绕过 ORM 框架直接用 JDBC 的Statement和ResultSet做游标遍历。核心代码像下面这样// 关键点设置 ResultSet 的类型和并发模式 Statement stmt connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY ); stmt.setFetchSize(100); // 每次从数据库取 100 行到客户端缓冲 ResultSet rs stmt.executeQuery(sql); int count 0; while (rs.next()) { // 处理单行数据比如写入 Excel 或者拼接 CSV handleRow(rs); if (count % 1000 0) { // 每批处理完主动释放局部引用帮助 GC 回收 } } rs.close(); stmt.close();这段代码要注意的点很多但最重要的一个隐藏参数是useCursorFetch。在 MySQL 的 JDBC 驱动Connector/J里要想让fetchSize真正生效必须先在连接 URL 上加上jdbc:mysql://host:port/db?useCursorFetchtrue不配置这个参数的时候驱动会无视设置的fetchSize直接把全量结果拉到客户端。有人做过对比测试同样的 SQL 同样一百万行数据不开useCursorFetch内存占用 2GB 以上开了之后稳定在 30MB 左右。差别就是这么大。2.2 方案二MyBatis 流式查询 ResultHandler听起来 JDBC 原生写法是最可控的但绝大多数项目都用了 MyBatis让它去手写 JDBC 既不现实也不符合团队代码风格。MyBatis 其实提供了对流式查询的封装核心思路是配合org.apache.ibatis.session.ResultHandler接口让 MyBatis 在遍历 ResultSet 时逐行回调处理逻辑。先定义 Mapper 接口方法public interface OrderMapper { void scanOrders(Param(startTime) String startTime, Param(endTime) String endTime, Param(handler) ResultHandlerOrderDO handler); }对应的 XML 写法select idscanOrders resultTypecom.example.OrderDO fetchSize-2147483648 SELECT * FROM t_order WHERE create_time BETWEEN #{startTime} AND #{endTime} /select注意这里有个反直觉的参数——fetchSize-2147483648。在 JDBC 规范里Integer.MIN_VALUE是 MySQL 驱动识别“流式模式”的固定标志只有 fetchSize 被设置成这个特殊值时驱动才会强制走流式读取。虽然 MyBatis 也允许你配置成一个正数如fetchSize500但如果连接 URL 上没有useCursorFetchtrue正数的 fetchSize 在 MySQL 下完全无效而Integer.MIN_VALUE这个魔数则不受该参数限制属于驱动写死的逻辑。实际使用的时候在 Service 层这样写public void exportOrders(String startTime, String endTime) { orderMapper.scanOrders(startTime, endTime, new ResultHandlerOrderDO() { Override public void handleResult(ResultContext? extends OrderDO context) { OrderDO order context.getResultObject(); // 每拿到一行立刻写入 Excel/CSV excelWriter.writeRow(order); // 关键处理完一定调用 context.stop() 判断是否需要提前终止 } }); }这种方式的好处是代码侵入性小——Mapper 接口正常定义XML 正常写唯一的变化是返回值变成 void、方法多了一个 ResultHandler 参数。团队看到这个结构就能明白这是在做流式处理后面维护起来也不会有人“好心”把循环改成return mapper.selectList()然后一次性收集所有数据。2.3 两种方案怎么选一个通用判断标准直接给一张对比表节省你纠结的时间对比维度JDBC 原生游标MyBatis ResultHandler代码侵入性高需要手写连接、关闭、异常处理低复用已有 Mapper 体系参数控制精细度高可自由调整 fetchSize依赖 XML 配置调整不够灵活缓存机制影响完全绕过一级缓存不经过 SqlSession 缓存天然不受缓存污染事务边界控制需要手动管理容易漏关 ResultSet由 SqlSession 和 Spring 事务统一管理适合场景临时脚本、数据迁移、单次导出常规业务接口、团队协作项目我的建议是如果是写一次性脚本或者做数据迁移JDBC 原生方式更直接如果是线上业务接口强烈推荐 MyBatis ResultHandler因为它在保持代码组织性的同时把流式查询的复杂度封装到了框架内部团队维护成本最低。而且 Spring 管理事务时MyBatis 的SqlSession和Connection生命周期是自动绑定的你只需要确保 mapper 方法调用结束后连接会正常归还连接池即可。3. 实操全程从配置到代码一步步落地流式导出3.1 第一步连接层参数必须配对不管选哪种方案连接参数的配置都是地基。先列出 MySQL 场景下的完整配置清单# 连接 URL 关键参数 spring.datasource.urljdbc:mysql://your-host:3306/your-db?useCursorFetchtrueuseUnicodetruecharacterEncodingutf8rewriteBatchedStatementstrueuseCompressiontrueuseCursorFetchtrue让 MySQL 驱动启用“服务端游标”fetchSize 才能生效。rewriteBatchedStatementstrue如果你后续写入也用批量方式这个参数能让 insert 语句重写为多值插入性能翻几倍。useCompressiontrue流式查询虽然每次只取一部分数据但网络往返次数变多压缩传输协议能显著减少网络传输量尤其在高延迟环境下效果明显。很多人配了useCursorFetchtrue之后还会漏一个动作——给 Statement 设置fetchSize。注意fetchSize不是越大越好。如果一次拉取 5000 行每次传输的包变大但数据库服务端需要维持一个更大的结果集快照如果一次只拉 10 行网络往返次数暴增导出速度会慢得让人怀疑人生。实践经验是内部网络环境下设置为 200 到 500 之间比较均衡既能保证吞吐又不会让客户端内存被顶上去。3.2 第二步用 MyBatis 完整实现一个百万级订单导出以一个真实的订单导出功能为例从 Controller 到 Mapper 完整走一遍。Controller 层不用多解释接收导出请求、调用 Service、返回响应即可。重点看 Service 层的实现Service public class OrderExportService { Resource private OrderMapper orderMapper; Resource private ExcelWriterFactory excelWriterFactory; public void exportOrders(LocalDateTime start, LocalDateTime end, HttpServletResponse response) throws IOException { // 设置导出响应头 response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); String fileName URLEncoder.encode(orders_ System.currentTimeMillis(), UTF-8); response.setHeader(Content-Disposition, attachment; filename fileName .xlsx); // 使用 EasyExcel 的流式写模式对应 POI 的 SXSSFWorkbook try (ExcelWriter writer EasyExcel.write(response.getOutputStream(), OrderExcelVO.class) .inMemory(false) // 关键不使用内存模式数据落盘到临时文件 .build()) { WriteSheet sheet EasyExcel.writerSheet(订单数据).build(); // 流式查询逐行处理 orderMapper.scanOrders(start, end, new ResultHandlerOrderDO() { Override public void handleResult(ResultContext? extends OrderDO context) { OrderDO order context.getResultObject(); OrderExcelVO vo convert(order); // 类型转换 writer.write(Collections.singletonList(vo), sheet); // 每处理 5000 行可以打一次日志观察进度 if ((context.getResultCount() % 5000) 0) { log.info(已导出 {} 行, context.getResultCount()); } } }); } finally { // 流式查询结合导出时异常清理逻辑放在这里 // 但 SqlSession 的关闭交给 Spring 管理不需要手动处理 } } }这段代码里有一个非常容易被忽略、但极其重要的设置——EasyExcel的.inMemory(false)。如果你用的是 POI 的 SXSSFWorkbook它默认就是流式写每写若干行会 flush 到磁盘而 EasyExcel 如果不显式设置inMemory(false)有些版本默认会在内存里积累数据结果就是查询端的内存被流式查询控制住了但写入端又变成了内存杀手。两边同时做流式处理才能保证整个导出过程的内存曲线是一条平线。3.3 第三步注意“单次查询”与“连接池”的相互影响流式查询成功之后还有一个隐性坑查询没有结束之前底层的数据库连接是拿不到第二件事去做的。因为游标是在服务端保持打开状态应用要一条条拉取连接必须一直保持活跃。这就意味着如果你在流式查询中间去调用另一个需要数据库连接的业务方法而连接池的最大连接数是 10有 5 个线程同时在做流式导出那么剩余连接可能会被其他请求占满新的流式查询只能在池外等待。排查这类问题可以通过两个手段一是看连接池活跃数监控二是在导出期间观察数据库show processlist可以看到大量的Sending data状态线程。处理原则是流式查询的过程里绝对不要再去获取新的数据库连接。如果导出数据需要关联查其他表要么在流式查询开始之前把关联数据一次性加载到内存Map 缓存要么等当前流式查询结束后再处理。这里我实际踩过一次坑事情本身不是很大但很典型——有一次导出功能上线后线上出现间歇性的连接池耗尽告警排查了半天最后发现是一个同事在ResultHandler回调里调了一个selectById的 mapper而当时流式查询的游标还没关连接池里的连接被 30 个导出任务全部占住其他业务全部等不到连接。后来在 code review 环节加了硬性规定流式查询回调里不允许再次访问数据库。3.4 第四步结果集关闭的正确姿势很多人以为 MyBatis 的流式查询会自动关闭 ResultSet实际上 MyBatis 只在SqlSession.close()时才会释放游标。如果你的 Service 方法在ResultHandler处理过程中抛了个异常而 Spring 事务恰好配置成不回滚那么这个连接会一直持有游标直到超时严重时数据库端积累大量未关闭的游标内存只增不减。以下是安全关闭的检查清单确保使用Transactional且事务边界覆盖整个流式查询过程让 Spring 在事务提交/回滚时统一释放连接。如果不用事务必须手动在finally里调用SqlSession.close()或者在 Service 方法里try-with-resources包裹。对 MySQL 而言连接的wait_timeout一般默认 8 小时流式查询如果中途网络断了服务端游标要等到超时才会释放。此时可以在 JDBC URL 里设置socketTimeout600001 分钟避免网络假死导致的连接泄漏。4. 进阶经验流式查询在真实项目中的五个关键坑4.1 坑一Logback 或日志打印会拖垮流式查询这个坑很多人不会注意到。当你在ResultHandler里打印日志比如log.info(处理到第{}行: {}, context.getResultCount(), order.getOrderNo())看似无害但在百万数据量下每行都输出日志单是日志 IO 就能让导出从 10 秒变成 5 分钟。更糟的是如果日志框架刚好在异步队列积压到缓冲区上限它会反过来阻塞业务线程而数据库游标又一直在保持连接多重因素叠加整个导出事务会被拖到超时。经验做法是流式处理中只记录分段日志每 5000 行或 10000 行输出一次总进度不打印明细。遇到需要排查的具体问题用条件断点或额外参数打开 debug 日志而不是在生产环境全量打。4.2 坑二Oracle 和 PostgreSQL 的流式机制并不相同各个数据库的流式查询实现差异很大。MySQL 靠Statement.setFetchSize(Integer.MIN_VALUE)或者useCursorFetchtrue生效Oracle 靠的是Statement.setFetchSize()加上 ResultSetTYPE_FORWARD_ONLY但默认驱动行为也不是完全流式需要手动确认PostgreSQL 则有两种模式一种是游标模式另一种是通过setAutoCommit(false)配合fetchSize实现单行流式读取。如果你的系统需要兼容多种数据库建议封装一层 DAO 接口把数据库差异隔离在实现里。比如定义public interface StreamingQueryTemplateT { void query(String sql, RowMapperT rowMapper, ConsumerT consumer); }然后用MySqlStreamingTemplate和OracleStreamingTemplate分别实现选数据源时注入不同 Bean。虽然前期多写一点适配代码但后续换数据库或者做的项目复用时收益立刻体现出来。4.3 坑三连接池参数没调照样被打挂数据库连接都有自己的生命周期。默认情况下 HikariCP 的maximumPoolSize10minIdle10看起来连接是够用的。但流式查询会让单个连接占用的时间变长——比如原来一条普通查询 10ms 就释放连接现在流式导出 100 万行可能要占用连接 60 到 90 秒。在导出任务并发量高的时候线程一多连接池很容易被占满。建议为导出任务建立独立的连接池配置或者直接分配给一个专门的数据源。使用 HikariCP 时可以这样配置spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 10000 validation-timeout: 3000如果导出是定时任务触发的可以在调度系统层面加一个全局并发限制保证同一时间最多 N 个导出任务在跑从源头控制连接和内存占用。4.4 坑四大字段会让单行内存“失控”流式查询虽然每行数据只占用单行内存但这一行如果包含一个 10MB 的TEXT或BLOB字段那么单行内存就会变成 10MB。一万行这样的数据在流式查询下同时只存在一行容器内存虽然在水平线上但单次处理大字段的耗时和垃圾回收压力会明显增加。遇到包含大字段的表导出前可以用 SQL 先剔除大字段列或者把大字段单独拆出来用分页查询处理。比如-- 注意不要 SELECT *只查询导出需要的列 SELECT order_no, user_id, product_name, amount, status, create_time FROM t_order WHERE create_time BETWEEN #{startTime} AND #{endTime}那些业务上根本不会展现在 Excel 里的remark字段留着只会成为导出的累赘。这点在真实项目里太常见了很多人习惯SELECT *一把梭结果内存压力全被无用的长文本字段拉满了。4.5 坑五大数据量下“分页查询”不等于“流式查询”这是很多人最容易混淆的概念。分页查询LIMIT offset, size虽然也是一次取一部分但它的缺陷在于 offset 越大MySQL 扫描的数据越多性能急剧下降——前 100 万行数据可能 1 秒内查完到第 900 万行时一个分页查询就要跑十几秒。而且分页查询每一次都单独构建一次完整的结果集虽然单页内存不爆但总耗时远比流式查询高。如果你的业务本来就有“翻页”需求那是分页但如果目的是“导出全量数据”一定要用流式或游标式查询。判断标准很简单导出不是给用户翻页看的没必要为了维护“页码”的概念付出毫无意义的性能代价。5. 问题排查与调优速查表OOM 定位不靠猜不管代码写得多小心总会有意想不到的情况。与其在 OOM 发生之后手忙脚乱地看日志不如把排查路径前置做成一张速查表。先看现象再对应原因能省很多时间。故障现象可能原因排查手段解决办法导出 1 万行正常10 万行就 OOM查询是普通模式没有进入流式用 Arthas 或 JProfile观察堆内存曲线看是否快速拉升到峰值检查连接 URL 是否带useCursorFetchtrue检查 Mapper XML 是否配置 fetchSize导出过程内存不高但导出完成后 Full GC 频繁写入端Excel/POI把数据堆到内存里看 dump 文件内存大量是org.apache.poi.xssf相关对象用.inMemory(false)或 SXSSFWorkbook 的窗口模式流式查询仿佛没生效日志里每行都出现ResultHandler 回调里打印了明细日志看日志打印频率查看每行日志时间间隔改成“每 5000 行打一次日志”多个导出任务并发时其他接口变慢连接池被流式查询占满查看数据库连接数和线程执行的 SQL 状态独立数据源 限制导出发并发数数据库连接数疯涨且Sending data状态多游标未关闭连接未释放show processlist看连接存活时间加socketTimeout确保事务边界覆盖流式查询导出速度越来越慢但内存正常分页查询 offset 过大看 SQL 执行计划扫描行数是否和 offset 同步增长改用流式或者游标式全表扫描除了这些线上问题还有一类经常出现的问题是“理论上代码没错但 OOM 依然发生”。这种情况下最快的手段是直接抓一个 heap dump 来看。常用的方法是用jmap -dump:formatb,fileheap.hprof pid虽然 dump 本身也比较耗资源但一次性可以把“谁会占用内存”看得清清楚楚。实际项目里我遇到过一个很典型的例子有个定时任务每天凌晨导出前一天的订单数据结果每天早上都会内存告警。看了堆转储发现大量LinkedHashMap对象堆积。顺藤摸瓜查到是某个工具类在导出过程中把所有行的数据都缓存到了一个静态缓存里用来做“数据对比”。这个功能本意是好的但开发者没意识到当数据量到百万级时这个静态缓存就是压垮内存的元凶。最后把对比逻辑改成分批拉取 分批对比内存问题直接消失。所以在优化流式查询时永远要记住一个原则不只查询端要流式处理端、写入端、缓存端都要流式。任何一环还在批量收集内存风险就依然存在。6. 最后的落地建议如何在自己项目里快速验证流式查询如果你刚从这篇文章开始动手我建议不要一上来就改生产代码先在一个独立的测试环境里做一次“对照实验”。具体做法分三步。第一步准备两张表一张数据量在 50 万行左右一张在 200 万行左右字段尽量贴近真实业务包含几个VARCHAR(255)字段和若干索引。第二步分别用两种方式查询同一份数据一种是常见的ListMap一次性查询另一种是流式查询 ResultHandler。在导出过程中用jstat -gcutil pid 1000观察堆内存占用和 GC 次数记下两个关键指标内存峰值和导出总耗时。第三步把两种方式的指标对比一下。你会发现一次性查询的内存可能达到 2GB 以上而流式查询的内存占用不超过 50MB但流式查询的总耗时可能会比一次性查询慢 10% 到 20%因为多出了网络往返和逐行处理。这个“慢一点但稳定不崩”的取舍对绝大多数生产业务来说都是划算的——毕竟没人愿意在导出 500 万行数据时等来一个 OOM。如果你担心流式查询带来的性能损耗还可以做一点优化在 MySQL 侧对导出的时间范围字段建立合适的索引确保查询本身不是全表扫描同时考虑在业务低峰期执行导出任务避开数据库负载高峰期。把这些因素都考虑进去之后我个人在实际操作中的体会是流式查询通常比很多人的预期要快得多——真正拖慢导出进度的往往是那些没有索引的 WHERE 条件、无谓的大字段查询以及不合时宜的日志输出。最后再分享一个小技巧流式查询的ResultHandler里可以通过ResultContext的stop()方法实现“数据量达到阈值就提前终止”的效果。比如导出时发现某一天的数据量异常就设置一个上限超过 100 万行就终止导出并打一个告警日志。这样做既能保护内存又能防止异常数据量打爆文件系统或者拖垮下游的 Excel 处理工具。这个需求用传统查询实现起来很别扭但在流式模式下只需要一行代码属于“用起来才知道有多顺手”的细节功能。
延伸阅读

更多相关文章

2026/10/8 16:06:48

模糊决策改进粒子群算法求解微网多目标优化调度策略

做微网调度的人恐怕都经历过这种纠结:优化目标里既要算经济账,又要盯环保指标,时不时还冒出电压偏移、储能寿命这些附加项,每个指标量纲完全不同,权重怎么给都感觉不对。我当初在“基于模糊决策法改进粒子群算法的微网…

2026/10/8 16:06:48

零显卡也能跑AI视频流水线:API+开源工具实战指南

几个月前,我们三个人的小团队接了一堆视频生产的活:产品宣传片翻新、客户案例拆条、短视频日常分发,每周都要稳定出好几条成片。摆在面前的问题是:公司没批显卡采购预算,工位上只有几台普通开发机,机房连个…

2026/10/8 16:06:48

校篮球联赛系统实战:Java后端+微信小程序实现赛程编排与实时比分

简介:这份资源是面向高校计算机相关专业毕业设计场景的完整项目包,主题为基于微信小程序的校篮球联赛系统,适合正在准备毕设、需要可运行案例与配套代码参考的本科或高职学生。项目采用Java后端与微信小程序前端组合,覆盖球队、球…

2026/10/8 16:57:02

claude-mem:为Claude Code打造跨会话长期记忆的AI编程助手

我和大多数人一样,最开始用Claude Code写东西都是开一个窗口聊到天荒地老,聊完了这个窗口就废弃了,下一次再开新窗口重新讲一遍项目背景、技术栈、踩过的坑。重复几轮之后我实在觉得不对劲,才开始找能跨会话长期记忆的解决方案。c…

2026/10/8 16:57:01

给Claude装上长期记忆:claude-mem原理、部署与避坑指南

每次打开一个新对话,Claude 就像被格式化了一样,完全不记得上一轮我们讨论过的方案、约定过的偏好、排查到一半的问题。这个问题在长周期的项目里特别痛,我也试过手动把背景摘要粘进每次 prompt,但项目一多就变成灾难。后来我接触…

2026/10/8 16:57:01

AI写代码总翻车?用流水线式提示词工程让结果可预期

1. 为什么不能随口让AI写代码 1.1 一个真实的“安排失败”现场 先从我最近一次给同事培训说起。同事打开对话框,对着AI敲了一句:“帮我写一个用户登录接口,要有JWT。”AI很快给了一段代码,但用的是Express jsonwebtoken&#xf…

2026/10/8 16:57:01

在线算命网站源码2016免费版:排盘算法与MySQL建站实战

简介:这是一套面向个人站长与PHP/ASP建站爱好者的娱乐型算命网站整站源码,版本为2016免费版H1.0,适合想快速搭建起卦排盘、周公解梦、手机号与QQ号吉凶测试等趣味查询站点的用户,源码开源可自由修改,无需复杂安装即可上…

2026/10/8 16:57:01

从随口问AI到五阶段流水线:打造稳定可用的AI辅助开发流程

1. 为什么“随口问 AI”永远得不到你想要的代码1.1 “帮我写个订单功能”背后的三大坑最近很多朋友跑来问我:为什么用 AI 写代码总是“翻车”?同一个模型,别人三句话就能生成一段能跑的代码,自己噼里啪啦敲了一大段需求&#xff0…

2026/10/8 16:52:01

Java毕设实战:驾校理论模拟考试系统源码全解析

简介:这是一份基于Java开发的驾校理论课模拟考试系统完整毕设源码,面向计算机、自动化等相关专业学生,适合用于毕业设计、期末课程设计或课程大作业,核心功能覆盖科目一与科目四,包含顺序练习、随机练习、单选题与判断…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑