mybatis批量更新默认不返回准确受影响行数,需同时配置jdbc的useaffectedrows=true和mybatis执行器为simple或reuse;推荐使用updatewrapper.in()单sql方式,可精准返回真实变更行数。

MyBatis 批量更新默认不返回准确受影响行数,主要受执行器类型和 JDBC 配置影响。要拿到真实更新条数,需从两个层面配合调整:JDBC 连接参数 + MyBatis 执行器配置。
关键原因:BATCH 执行器会丢失行数
MyBatis 默认使用 SIMPLE 执行器,但很多项目显式配置为 BATCH 以提升批量性能。而 BATCH 模式底层调用 Statement.addBatch() + executeBatch(),JDBC 规范规定此时 executeBatch() 返回的是每条语句的更新计数数组——但 MyBatis 的 update() 方法只返回一个整数,且在 BATCH 模式下常统一返回 -1 或被截断。
- BATCH 模式适合高吞吐写入,但放弃行数反馈
- 若业务强依赖“到底改了几行”,就不能用 BATCH 执行器
- REUSE 和 SIMPLE 模式可正常返回影响行数
必须配置 JDBC 的 useAffectedRows=true
即使执行器设为 SIMPLE,MySQL 驱动默认返回的是“匹配行数”(matched rows),而非“真正变更的行数”(changed rows)。比如字段值本来就是 20,再 SET age=20,MySQL 默认返回 1(匹配),但业务通常想要的是 0(未变更)。
解决办法是在数据库连接 URL 中添加参数:
jdbc:mysql://host:3306/db?useAffectedRows=true- 该参数让 MySQL 驱动调用
mysql_affected_rows()而非mysql_info() - Oracle、PostgreSQL 等数据库无需此参数,原生支持返回变更行数
- Spring Boot 中可在
application.yml的spring.datasource.url后追加
两种推荐的批量更新方式及返回行为
方式一:用 UpdateWrapper.in() 单次 SQL 更新(推荐)
生成一条含 WHERE id IN (1,2,3) 的 UPDATE 语句,本质是单条 SQL,天然支持返回真实影响行数。
- 代码简洁,事务安全,网络开销小
- 返回值即实际被修改的记录数(如 3 条 ID 存在且字段值有变化,才返回 3)
- 注意:null 字段默认不参与更新,需用
wrapper.setNull("col")显式置空
方式二:用 updateBatchById()(慎用行数)
MyBatis-Plus 提供的该方法底层仍是循环执行单条 UPDATE,但受执行器影响大:
- 若全局配置了
defaultExecutorType=BATCH,它仍可能返回 -1 - 确保执行器为 SIMPLE 或 REUSE,且 JDBC 含
useAffectedRows=true,才能获得准确总数 - 不适合超大批量(如 >1000 条),易触发 GC 或连接超时
验证是否生效的小技巧
执行一次批量更新后,打印返回值并手动查库比对:
- 插入测试数据:
INSERT INTO user(id, name, age) VALUES (1,'a',18), (2,'b',18), (3,'c',25); - 执行
UPDATE user SET age=18 WHERE id IN (1,2,3); - 正确配置下应返回 2(ID=1、2 的 age 原值非 18,被更新;ID=3 原值已是 18,不变更)
- 若返回 3,说明
useAffectedRows=true未生效 - 若返回 -1,检查
defaultExecutorType是否为 BATCH











