Spring JdbcTemplate批量操作实战:原理、性能优化与避坑指南
1. 从单条到批量为什么我们需要关注数据库操作的效率在Java后端开发尤其是基于Spring框架的项目里数据库操作是业务逻辑的基石。我们每天都在写insert、update、delete当数据量小、并发低的时候单条执行JdbcTemplate.update()代码清晰逻辑简单似乎没什么问题。但真实的生产环境往往不是这样。我经历过一个数据同步的场景需要将上游系统推送过来的数万条用户状态变更记录更新到本地数据库。最初的版本就是简单的for循环一条一条地执行UPDATE语句。结果呢接口超时数据库连接池被打满监控告警响个不停。那次线上事故让我彻底明白在数据处理面前效率不是可选项而是必选项。批量操作的核心价值就在于将多次网络往返和数据库事务开销压缩到一次或少数几次中。想象一下你要给1000个朋友每人寄一封信。单条操作就像你每次只拿一封信开车去邮局寄出再回家拿下一封。而批量操作则是你把1000封信整理好一次性带到邮局通过一个窗口全部处理完毕。后者节省的不仅仅是汽油网络IO还有你往返的时间事务上下文切换和邮局窗口的资源数据库连接和锁竞争。Spring JdbcTemplate提供的批量更新能力正是为我们封装好了这辆“卡车”和“绿色通道”。很多人知道JdbcTemplate有batchUpdate方法但用起来却感觉“没那么快”或者遇到一些奇怪的异常。这通常是因为只知其然而不知其所以然。批量操作不仅仅是把SQL扔进一个列表那么简单它涉及到JDBC驱动层的实现、数据库的批处理协议、事务的边界控制以及非常重要的——参数列表的匹配。接下来我会结合我踩过的坑和优化经验从原理到实践拆解如何真正高效地使用Spring JdbcTemplate进行批量新增和更新。2. JdbcTemplate批量操作的底层机制与性能瓶颈分析要玩转批量首先得知道它到底是怎么工作的。JdbcTemplate.batchUpdate方法最终会调用到java.sql.Statement或java.sql.PreparedStatement的addBatch和executeBatch方法。这里有个关键点JdbcTemplate的批量操作默认是基于PreparedStatement的。这意味着SQL语句会先被预编译然后通过设置不同的参数多次添加到批处理中最后一次性执行。2.1 JDBC批处理的两种模式与驱动实现差异不同的数据库和JDBC驱动对批处理的实现支持程度不同这直接影响了性能。标准批处理addBatch/executeBatch这是最常见的方式。PreparedStatement预编译一条SQL然后通过setXXX方法循环设置每一组参数并调用addBatch()。积累到一定数量后调用executeBatch()一次性发送给数据库。数据库服务器接收后可能会将其作为一个批处理单元执行。但请注意这并不总是意味着在数据库内部是“一条命令”。对于MySQL在默认配置下驱动会将批处理操作在客户端拆分成多条语句然后拼接成如INSERT INTO table VALUES (...), (...), (...)的多值语句或者依然是分多次网络包发送这取决于连接参数rewriteBatchedStatements。驱动特定的批处理优化以MySQL的Connector/J驱动为例其性能瓶颈曾经非常明显。在早期版本或未优化配置时executeBatch()实际上是在内部循环执行每条语句几乎没有性能提升。关键参数rewriteBatchedStatementstrue必须被启用。这个参数会让驱动尝试重写批量语句。对于INSERT它会将其重写为多值语句对于UPDATE和DELETE虽然无法重写为单一语法但能优化网络包发送方式减少网络往返。启用这个参数后批量插入的性能提升可能是数量级的。注意rewriteBatchedStatements参数是MySQL驱动的“魔法开关”。对于批量插入效果立竿见影。但对于批量更新其优化方式不同性能提升主要来自于减少了网络延迟而非SQL重写。其他数据库如PostgreSQL的JDBC驱动PgJDBC对批处理有原生良好支持通常不需要特殊参数。2.2. JdbcTemplate.batchUpdate 方法族详解JdbcTemplate提供了多个重载的batchUpdate方法最常用的是以下两种batchUpdate(String sql, final BatchPreparedStatementSetter pss)这是最经典、最灵活的方式。你需要实现BatchPreparedStatementSetter接口在其setValues方法中为每一次批处理设置参数并指定总批次数getBatchSize。jdbcTemplate.batchUpdate( UPDATE user SET status ? WHERE id ?, new BatchPreparedStatementSetter() { Override public void setValues(PreparedStatement ps, int i) throws SQLException { User user userList.get(i); ps.setString(1, user.getStatus()); ps.setLong(2, user.getId()); } Override public int getBatchSize() { return userList.size(); } } );优点完全控制每一次参数设置的过程适合复杂对象到SQL参数的映射。缺点需要编写匿名内部类代码稍显冗长。batchUpdate(String sql, final ListObject[] batchArgs)这种方式更简洁。你提供一个ListObject[]列表中的每个Object[]对应一组SQL参数。ListObject[] batchArgs new ArrayList(); for (User user : userList) { batchArgs.add(new Object[]{user.getStatus(), user.getId()}); } jdbcTemplate.batchUpdate(UPDATE user SET status ? WHERE id ?, batchArgs);优点代码简洁直接使用参数列表。缺点参数顺序必须严格与SQL占位符?对应容易因顺序错误导致bug。性能瓶颈分析网络往返Round-Trips未启用批处理优化时N条语句产生N次网络通信这是最大的开销。事务日志Transaction Log每条语句都可能产生独立的事务日志如果未在同一个事务中批量操作可以合并日志写入减少磁盘IO。数据库锁竞争逐条更新可能长时间锁住数据行或索引而设计良好的批量操作可能减少锁的持有时间但大事务也可能导致锁升级需要权衡。内存与批大小Batch Size一次性将10万条数据加入批处理会消耗大量客户端内存并可能使数据库端事务过大。需要分批次进行。3. 实战高效批量更新与新增的完整代码与配置理解了原理我们来看如何落地。我将以一个用户信息批量更新和商品批量入库的场景为例展示完整的代码和配置。3.1. 环境准备与关键配置首先确保你的数据源配置正确启用了批处理优化。以Spring Boot配置MySQL为例# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/your_db?useUnicodetruecharacterEncodingutf8useSSLfalserewriteBatchedStatementstrueserverTimezoneAsia/Shanghai username: root password: your_password hikari: maximum-pool-size: 20 connection-timeout: 30000关键就是rewriteBatchedStatementstrue。对于HikariCP连接池保持合理的连接数也很重要因为批量操作可能会占用连接稍长时间。3.2. 场景一批量更新用户状态假设我们有一个ListUser需要根据ID更新其状态字段。方案A使用BatchPreparedStatementSetter推荐用于复杂逻辑Service public class UserBatchUpdateService { Autowired private JdbcTemplate jdbcTemplate; public int[] batchUpdateUserStatus(ListUser users) { if (users null || users.isEmpty()) { return new int[0]; } String sql UPDATE t_user SET status ?, update_time NOW() WHERE id ?; return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { Override public void setValues(PreparedStatement ps, int i) throws SQLException { User user users.get(i); ps.setString(1, user.getStatus()); // 第一个占位符 ps.setLong(2, user.getId()); // 第二个占位符 // 这里可以设置更多参数或者进行一些值转换 } Override public int getBatchSize() { return users.size(); } }); } }返回值int[]这个数组的长度等于批次数每个元素表示对应SQL语句影响的行数。对于UPDATE通常是0未找到或1成功更新。但需注意根据数据库和驱动有些情况下可能返回Statement.SUCCESS_NO_INFO-2。方案B使用参数列表适合简单映射public int[] batchUpdateUserStatusSimple(ListUser users) { ListObject[] batchArgs users.stream() .map(user - new Object[]{user.getStatus(), user.getId()}) .collect(Collectors.toList()); String sql UPDATE t_user SET status ?, update_time NOW() WHERE id ?; return jdbcTemplate.batchUpdate(sql, batchArgs); }3.3. 场景二批量新增商品信息批量插入是性能收益最明显的场景。假设我们要插入ListProduct。public void batchInsertProducts(ListProduct products) { String sql INSERT INTO t_product (product_code, product_name, price, category) VALUES (?, ?, ?, ?); jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { Override public void setValues(PreparedStatement ps, int i) throws SQLException { Product product products.get(i); ps.setString(1, product.getCode()); ps.setString(2, product.getName()); ps.setBigDecimal(3, product.getPrice()); ps.setString(4, product.getCategory()); // 确保没有漏掉字段顺序与SQL中的VALUES一一对应 } Override public int getBatchSize() { return products.size(); } }); }重要提示对于海量数据例如超过5000条的插入不建议一次性提交。过大的批处理会占用大量内存并可能导致数据库事务日志暴增。应该采用分批次提交的策略。3.4. 进阶分批次处理与事务控制这是生产级应用必须考虑的点。我们结合Spring的Transactional注解和手动分页来实现。Service public class BulkDataService { Autowired private JdbcTemplate jdbcTemplate; // 批次大小可根据数据库性能调整通常1000-5000是一个平衡点 private static final int BATCH_SIZE 2000; Transactional(rollbackFor Exception.class) public void batchInsertProductsInBatches(ListProduct allProducts) { // 计算总批次数 int total allProducts.size(); int batchCount (total BATCH_SIZE - 1) / BATCH_SIZE; // 向上取整 for (int i 0; i batchCount; i) { // 截取当前批次的数据 int fromIndex i * BATCH_SIZE; int toIndex Math.min(fromIndex BATCH_SIZE, total); ListProduct batchList allProducts.subList(fromIndex, toIndex); // 执行当前批次的插入 String sql INSERT INTO t_product (...) VALUES (?,?,?,?); jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { Override public void setValues(PreparedStatement ps, int j) throws SQLException { Product p batchList.get(j); // ... 设置参数 } Override public int getBatchSize() { return batchList.size(); } }); // 可选每批提交后记录日志或清理内存 // entityManager.clear(); // 如果同时使用JPA需要清理持久化上下文 } // 整个方法在一个事务中所有批次要么全部成功要么全部回滚 } }事务边界上述方法被Transactional标注意味着整个分批次插入过程在一个数据库事务中。优点是数据一致性最强。缺点是如果数据量极大会产生一个超长事务占用大量undo日志空间在出错时回滚代价高。对于允许中间部分失败、最终一致性的场景可以考虑每批次一个独立事务但需要在业务逻辑层处理部分失败的重试或补偿。4. 性能对比实测与深度调优策略理论说了很多到底能快多少我设计了一个简单的对比实验。测试环境本地MySQL 8.0rewriteBatchedStatementstrueSpring Boot 3.x插入10000条记录。方式一循环单条插入for (Product p : productList) { jdbcTemplate.update(INSERT ... VALUES (?,?,?,?), p.getCode(), p.getName(), ...); }方式二JdbcTemplate批量插入如3.3节所示结果近似值单条插入约 12 秒批量插入约 0.8 秒性能提升超过15倍。这主要归功于rewriteBatchedStatements将10000条INSERT重写为大约INSERT INTO ... VALUES (...),(...),...的语句极大减少了网络和SQL解析开销。4.1. 影响性能的关键因素与调优批处理大小Batch Size不是越大越好。过大的批处理如10万会导致客户端内存压力大数据库端SQL语句过长可能超出max_allowed_packet限制引发错误。需要测试找到甜点。通常1000到5000条是一个不错的起点。可以编写测试循环测试不同批次大小如500, 1000, 2000, 5000下的耗时找到性能拐点。连接参数与驱动版本rewriteBatchedStatementsMySQL的“神器”必须为true。useServerPrepStmtscachePrepStmts对于重用率极高的PreparedStatement设置为true可以缓存服务端预处理语句带来额外性能提升。驱动版本始终使用较新的、稳定的JDBC驱动版本旧版本可能存在批处理bug或性能问题。数据库服务器配置max_allowed_packet确保该参数足够大以容纳重写后的大型SQL语句。可以设置为64M或更高。innodb_log_buffer_size和innodb_log_file_size对于大型批处理事务适当增大日志缓冲区和大日志文件可以减少日志写入磁盘的频率。autocommit在批处理操作期间确保处于手动事务控制Transactional下而不是自动提交模式否则每条语句都是一个独立事务性能极差。监控与诊断使用jdbcTemplate.setFetchSize(100)等设置对查询类批处理有影响但对更新/插入影响不大。关注数据库的慢查询日志看看批处理语句的执行时间。使用APM工具如SkyWalking, Pinpoint监控JDBC调用耗时确认时间主要消耗在数据库执行还是网络传输。5. 常见“坑”与最佳实践总结在实际使用中我遇到过不少问题这里总结一下希望能帮你避坑。坑1参数顺序错乱或数量不匹配这是最常见的运行时错误。SQL语句有5个?但你的Object[]只有4个元素或者setValues里少设了一个参数。务必仔细核对。建议使用常量或枚举来定义字段顺序或者在设置参数时添加清晰的注释。坑2忽略返回值或错误处理batchUpdate返回的int[]需要被关注。虽然大多数情况下我们只关心成功与否但某些业务场景可能需要根据影响行数做进一步判断。更重要的是批处理中某条SQL失败如违反唯一约束默认情况下会抛出BatchUpdateException但在此之前的语句可能已经执行成功。这取决于数据库和驱动的事务语义。对于要求强一致性的操作必须将整个批量操作放在一个数据库事务中。坑3海量数据内存溢出直接对一个包含50万条记录的List进行批处理会一次性在内存中构建巨大的参数列表或BatchPreparedStatementSetter。必须分批次处理如3.4节所示。可以从文件或流中读取数据读一批处理一批提交一批。坑4与JPA/Hibernate混合使用时的上下文污染如果你的项目同时使用了Spring Data JPA并且在同一个事务中先进行了JPA操作会与EntityManager交互然后又进行JdbcTemplate批量操作需要注意。JdbcTemplate操作不会自动同步到JPA的一级缓存PersistenceContext。反之JPA加载的实体状态也可能被JdbcTemplate的直接SQL更新绕过导致数据不一致。最佳实践是在批量JdbcTemplate操作后如果后续逻辑需要用到相关实体调用entityManager.clear()清空持久化上下文强制后续查询从数据库重新加载。最佳实践清单始终配置rewriteBatchedStatementstrueMySQL。为批量操作设置合理的批次大小如2000并对海量数据实现分批次逻辑。将批量操作置于事务控制之下根据业务需求选择是整个大事务还是每批小事务。仔细检查SQL和参数映射避免顺序和数量错误。在复杂场景下优先使用BatchPreparedStatementSetter以获得更清晰的代码控制。关注返回值与异常设计好批处理部分失败时的业务补偿或重试机制。进行性能测试在不同数据量和批次大小下找到最适合当前硬件和数据库配置的参数。考虑使用更专业的工具对于极其复杂或数据量巨大的ETL场景Spring JdbcTemplate的批处理可能仍显笨重。可以考虑使用Spring Batch框架它提供了更强大的分片Chunk、跳过Skip、重试Retry机制以及完善的作业管理和监控功能。最后技术选型没有银弹。Spring JdbcTemplate的批量操作在大多数业务系统的CRUD性能优化中是一个简单、直接且效果显著的手段。掌握其原理和细节能让你在应对数据密集型操作时更加从容。

相关新闻

数字滤波器核心原理与工程实现:从FIR/IIR到实战设计指南

数字滤波器核心原理与工程实现:从FIR/IIR到实战设计指南

1. 项目概述:从“信号”到“信息”的必经之路在电子工程、通信、音频处理乃至生物医学信号分析这些领域里,我们每天打交道最多的,可能就是那些看不见摸不着的“信号”。无论是手机接收的无线波、麦克风捕捉的声波,还是心电图机记录…

2026/8/5 4:06:44 阅读更多 →
动态范围:从原理到实战,全面解析成像系统的光影捕捉能力

动态范围:从原理到实战,全面解析成像系统的光影捕捉能力

1. 项目概述:从“过曝”与“死黑”说起每次拿起相机或者手机拍照,尤其是在光线对比强烈的场景下——比如逆光的人像、夕阳下的剪影,或者室内有明亮窗户的风景——我们总会遇到一个让人头疼的问题:要么天空一片惨白,细节…

2026/8/5 4:06:44 阅读更多 →
南昌市进贤县江山云起别墅,楼梯切割加装封闭式井道 定制黑武士内饰家用电梯落地案例

南昌市进贤县江山云起别墅,楼梯切割加装封闭式井道 定制黑武士内饰家用电梯落地案例

一、项目背景与用户需求本案例位于南昌市进贤县江山云起别墅小区,房屋为地上四层、地下两层的六层别墅户型。业主最初计划采购山东本地电梯工厂的产品,因自身企业地处山东,对当地供应链更为熟悉。直到业主看到邻居家落地的永通力家用电梯&…

2026/8/5 4:05:44 阅读更多 →

最新新闻

5分钟快速恢复QQ空间历史记录:GetQzonehistory终极指南

5分钟快速恢复QQ空间历史记录:GetQzonehistory终极指南

5分钟快速恢复QQ空间历史记录:GetQzonehistory终极指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否担心QQ空间里那些承载青春记忆的说说会随着时间流逝而消失&…

2026/8/5 11:44:16 阅读更多 →
终极泰拉瑞亚地图编辑器:10分钟从新手变造物主

终极泰拉瑞亚地图编辑器:10分钟从新手变造物主

终极泰拉瑞亚地图编辑器:10分钟从新手变造物主 【免费下载链接】Terraria-Map-Editor TEdit - Terraria Map Editor - TEdit is a stand alone, open source map editor for Terraria. It lets you edit maps just like (almost) paint! It also lets you change wo…

2026/8/5 11:44:16 阅读更多 →
Figma中文界面汉化终极指南:3分钟实现专业设计工具本地化

Figma中文界面汉化终极指南:3分钟实现专业设计工具本地化

Figma中文界面汉化终极指南:3分钟实现专业设计工具本地化 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 你是否在使用Figma时被英文界面困扰?专业术语难懂、菜单…

2026/8/5 11:44:16 阅读更多 →
从功能实现到工程化落地:异步任务与消息队列的实战应用

从功能实现到工程化落地:异步任务与消息队列的实战应用

1. 一个真实的项目复盘:从“功能跑通”到“工程落地”的鸿沟最近和几个刚入行的朋友聊天,发现一个挺普遍的现象:很多人,包括我自己刚工作时,都容易陷入一个误区——把“功能实现”等同于“项目成功”。比如&#xff0c…

2026/8/5 11:44:16 阅读更多 →
如何快速解决常见问题:RVC语音转换WebUI的7个终极技巧

如何快速解决常见问题:RVC语音转换WebUI的7个终极技巧

如何快速解决常见问题&#xff1a;RVC语音转换WebUI的7个终极技巧 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-Convers…

2026/8/5 11:44:16 阅读更多 →
CUDA编程入门:从.cu文件结构到并行计算实战

CUDA编程入门:从.cu文件结构到并行计算实战

1. 从“Hello, World!”到并行计算&#xff1a;CUDA编程的初体验如果你是一名C/C开发者&#xff0c;第一次接触CUDA编程&#xff0c;打开一个.cu文件时&#xff0c;可能会觉得既熟悉又陌生。它看起来就像普通的C代码&#xff0c;但里面多了些奇怪的修饰符&#xff0c;比如__glo…

2026/8/5 11:43:15 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架&#xff0c;为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能&#xff0c;同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求&#xff1a;通孔焊盘 十字花&#xff1b;过孔 Via 实心直连&#xff1b;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑&#xff1a;全部统一十字&#xff0c;导致接地过孔阻抗高、大电流发热&#xff01; 一、快捷键打开规则 PCB 界面按下&#xff1a;D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用&#xff0c;其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流&#xff1a;一个核心问题的诞生想象一下&#xff0c;你是一个城市供水系统的总工程师。你的城市有多个水源&#xff08;水库&#xff09;&#xff0c;需要通过一个复杂的地下管道网络&#xff0c;将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/4 11:41:39 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起&#xff1a;为什么我们需要互相关几年前&#xff0c;我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号&#xff0c;理论上它们接收到的声音波形应该非常相似&#xff0c;只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →