网易首页 > 网易号 > 正文 申请入驻

updateBatchById批量更新慢换写法快二十倍

0
分享至

批量更新 2000 条数据,updateBatchById 跑了 18 秒,接口直接超时。看了一眼日志,发现底层居然是一条一条发 UPDATE 语句。

MyBatis-Plus 的 updateBatchById 名字里带 "Batch",很多开发者就以为它走的是 JDBC 批量操作。实际上默认实现是逐条执行,跟 for 循环没区别。

问题出在 MyBatis-Plus 的批量方法默认走 sqlSession 的逐条模式,需要手动开启 rewriteBatchedstatements 和正确使用 SQLSession 批量提交才能真正提速。下面拆解两种正确写法。

一、默认行为的坑1. updateBatchById 的真相

看源码会发现,updateBatchById 内部调用的是 sqlSession.update(statement, entity),循环逐条执行:

// MyBatis-Plus 默认实现(简化)public boolean updateBatchById(Collection list) {for (T entity : list) {sqlsession.update(sqlStatement, entity); // 逐条执行}

2000 条数据就是 2000 次网络往返 + 2000 次事务提交,慢是必然的。

2. 实测数据对比

以 MySQL 8.0 + 本地环境测试 2000 条更新:

方式

耗时

SQL执行次数

updateBatchById(默认)

18.3s

2000次

手动批量(未开启rewrite)

4.2s

2000次(合并网络)

手动批量 + rewrite

0.8s

1次(合并SQL)

差距超过 20 倍,关键就在两个开关。

3. 两个必要配置

⚠️ 注意:JDBC URL 必须加 rewriteBatchedStatements=true,否则 JDBC 驱动不会把多条 SQL 合并成一条发送。

spring:datasource:url: jdbc:MySQL://localhost:3306/db?rewriteBatchedStatements=true&useServerPrepStmts=false

useServerPrepStmts=false 也很关键,服务端预编译模式下 rewrite 可能失效。

小结:默认 updateBatchById 没有批量能力,开启 rewrite 是第一步。

二、正确批量写法1. 手动 SqlSession 批量

最可控的方式是自己获取 SqlSession 执行批量:

@Servicepublic class UserService {@Autowiredprivate SqlSessionFactory sqlSessionFactory;public void batchUpdate(List list) {try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {UserMapper mapper = session.getMapper(UserMapper.class);for (int i = 0; i < list.size(); i++) {mapper.updateById(list.get(i));if (i % 500 == 0) {session.flushStatements();session.commit();session.flushStatements();session.commit();}

ExecutorType.BATCH 让 MyBatis 把多条同类型 SQL 合并发送,每 500 条 flush 一次避免内存溢出。

2. MyBatis-Plus 的 ServiceImpl

ServiceImpl 提供了 updateBatchById 的重载方法,传入 batchSize:

public class UserServiceImplextends ServiceImplimplements IUserService {@Overridepublic boolean updateBatch(List list) {return updateBatchById(list, 500);// ↑ 第二个参数是 batchSize}

这个方法内部也是用 ExecutorType.BATCH 的 SqlSession,不需要自己管理。

3. XML 的 foreach 方案

另一种思路是直接写批量 SQL,一次请求完成:

UPDATE userSET name = #{item.name}, age = #{item.age}WHERE id = #{item.id}

需要在 URL 加 allowMultiQueries=true,MySQL 才支持多条语句一次执行。

批量更新优先用 SqlSession(ExecutorType.BATCH) 方案,不依赖数据库特性,兼容性最好。

小结:三种批量写法各有适用场景,ExecutorType.BATCH 是最通用的选择。

三、避坑清单1. 事务范围控制

批量操作必须手动控制事务范围:

// 错误:每条自动提交SqlSession session = factory.openSession(ExecutorType.BATCH);// 正确:关闭自动提交SqlSession session = factory.openSession(ExecutorType.BATCH, false);

第二个参数 false 表示关闭自动提交,所有 SQL 在同一个事务里执行。

2. flush 时机

不 flush 会导致内存暴涨。每 500~1000 条 flush 一次是经验值:

if (i % 500 == 0) {session.flushStatements(); // 发送累积的 SQLsession.commit();          // 提交事务session.clearCache();      // 清理一级缓存}

clearCache 容易被忽略,一级缓存满了同样影响性能。

3. 与主键策略的关系

使用 IdType.ASSIGN_ID(雪花算法)批量插入没问题,但批量更新不涉及主键生成,所以主键策略对 updateBatch 无影响。需要注意的反而是乐观锁字段:

⚠️ 注意:如果实体有 @Version 乐观锁字段,批量更新时每次都会检查版本号,不能合并成一条 SQL。

小结:事务、flush 频率、缓存清理是批量操作的铁三角,缺一不可。

小结

MyBatis-Plus 批量更新慢的核心原因就两个:JDBC 没开 rewriteBatchedStatements,以及没用 ExecutorType.BATCH。两个配置加一行代码改动,性能提升 20 倍。

实际开发中,优先用 ServiceImpl 自带的 updateBatchById(list, 500),一行搞定。如果对性能有极致要求,自己管理 SqlSession 并配合 flush 策略。别忘了 URL 里那两个参数,这是所有批量操作的前提。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
韩国女爱豆舞台“手伸进裤子”引争议,直播道歉:没想太多就拉了

韩国女爱豆舞台“手伸进裤子”引争议,直播道歉:没想太多就拉了

草莓解说体育
2026-07-25 05:09:28
小菲北京抱小儿子去巡店,父爱满满,小宝宝趴爸爸肩膀萌萌哒!

小菲北京抱小儿子去巡店,父爱满满,小宝宝趴爸爸肩膀萌萌哒!

徐醇老表哥
2026-07-26 23:08:32
德仁天皇当众怒怼高市早苗:70年来头一遭,日本皇室要变天?

德仁天皇当众怒怼高市早苗:70年来头一遭,日本皇室要变天?

泪满过眼
2026-06-17 19:10:23
大码模特现实里到底多大?

大码模特现实里到底多大?

飛娱日记
2026-05-12 08:27:55
为什么Rain金泰熙、玄彬孙艺珍海外被拍,画风全变了?

为什么Rain金泰熙、玄彬孙艺珍海外被拍,画风全变了?

时光慢旅人
2026-07-27 01:01:00
梅洛尼成绩单出炉,欧洲目瞪口呆,和中国的生意,意大利一件没落

梅洛尼成绩单出炉,欧洲目瞪口呆,和中国的生意,意大利一件没落

起喜电影
2026-07-26 01:45:32
宝马拍视频内涵中国车企,这事儿体面吗?

宝马拍视频内涵中国车企,这事儿体面吗?

功夫AUTO
2026-07-24 17:02:07
前女友Coco曝谢氏父子私密事,原来是一类人

前女友Coco曝谢氏父子私密事,原来是一类人

莉莉和奶奶
2026-07-26 17:45:20
终于有经济学家批评体制内退休金太高、加剧代际矛盾,评论区炸锅

终于有经济学家批评体制内退休金太高、加剧代际矛盾,评论区炸锅

慧翔百科
2026-06-23 08:47:02
家中照片全被曝!鹿晗音乐节粉碎式回应司晓迪争议

家中照片全被曝!鹿晗音乐节粉碎式回应司晓迪争议

小邵说剧
2026-07-27 08:14:29
日本防相小泉出轨已婚少妇,不想家中老婆更风流,曾与外国人拍片

日本防相小泉出轨已婚少妇,不想家中老婆更风流,曾与外国人拍片

往史过眼云烟
2026-07-09 21:59:41
笑疯了!对3,要不起!证件都亮了,天作之合!第一个太卑鄙了

笑疯了!对3,要不起!证件都亮了,天作之合!第一个太卑鄙了

另子维爱读史
2026-07-16 20:53:22
比亚迪新员工爆料

比亚迪新员工爆料

新浪财经
2026-07-26 14:27:53
罗永浩痛批电视厂家长辈模式难用:不毁灭没天理

罗永浩痛批电视厂家长辈模式难用:不毁灭没天理

鞭牛士
2026-07-26 08:38:05
胡静在马来西亚的生活曝光:吃的水果,有一半大众都没见过!

胡静在马来西亚的生活曝光:吃的水果,有一半大众都没见过!

手工制作阿歼
2026-07-25 00:43:49
上海男篮续约王哲林替补遇阻,33岁老将索要三年合同,季后赛场均2.6分

上海男篮续约王哲林替补遇阻,33岁老将索要三年合同,季后赛场均2.6分

中国篮坛快讯
2026-07-26 16:04:24
“骑砍之母”İpek Yavuz不幸去世 终年54岁

“骑砍之母”İpek Yavuz不幸去世 终年54岁

3DM游戏
2026-07-27 07:05:09
油价调整:国际油价冲高回落,7月31日国内油价大幅上调几成定局

油价调整:国际油价冲高回落,7月31日国内油价大幅上调几成定局

有料财经
2026-07-26 19:13:36
北京的隐形土豪真的太多了

北京的隐形土豪真的太多了

微微热评
2026-07-25 18:34:05
百年大三甲,党委书记换帅!

百年大三甲,党委书记换帅!

医疗器械经销商联盟
2026-07-26 07:58:59
2026-07-27 09:32:49
呼呼历史论
呼呼历史论
分享有趣的历史
743文章数 17643关注度
往期回顾 全部

科技要闻

苹果眼镜目标WWDC2027亮相,摄像头成最难一关

头条要闻

牛弹琴:特朗普突然下令不打了 地主家的余粮真不多了

头条要闻

牛弹琴:特朗普突然下令不打了 地主家的余粮真不多了

体育要闻

詹姆斯的最后一集,依旧最艰难的路?

娱乐要闻

演员王建隆在家中去世,年仅43岁

财经要闻

不肯裁员的善人:西安商人严鹏之死

汽车要闻

轿跑姿态+大空间/标配655km续航 奇瑞风云A9置换价10.68万起

态度原创

房产
数码
亲子
手机
艺术

房产要闻

37人抢1套房…海棠湾资产拍卖,爆了!

数码要闻

小米获智能门锁、可视门铃、监控摄像头三大类销量第一

亲子要闻

怀孕的妈妈们认真看看哦!

手机要闻

vivo X300 E手机完整规格曝光

艺术要闻

毛岸英入朝前填写的简历,字迹神似毛主席,“家庭栏”令人落泪…

无障碍浏览 进入关怀版