MyBatis使用CASE WHEN进行批量更新的高效写法
作者:一勺菠萝丶
当我们使用mybatis的时候,可能经常会碰到一批数据的批量更新问题,因为如果一条数据一更新,那每一条数据就需要涉及到一次数据库的操作,包括网络IO以及磁盘IO,可想而知,这个效率是非常低下的,那么今天我们就来总结一下,如何使用mybatis做批量更新,需要的朋友可以参考下
在实际业务开发中,我们经常需要 批量更新多条数据。
最常见的做法是:
for (Item item : list) { mapper.update(item); }
但这样会执行多次 SQL,性能低下,尤其当更新上百条数据时,数据库压力很大。
有没有更高效的方式?
有!可以使用 SQL 的 CASE WHEN 批量更新写法。
一、为什么要用 CASE WHEN 批量更新?
传统循环更新的缺点:
- 每次执行一条
UPDATE
,频繁网络 IO。 - MyBatis 多次 prepare statement,效率低。
- 数据量大时,明显拖慢系统性能。
而 CASE WHEN
批量更新的优点:
- 一次 SQL 完成多条更新;
- 性能提升明显(尤其在上百条数据时);
- 减少数据库交互次数;
- 兼容 MyBatis 动态 SQL,非常灵活。
二、示例场景
假设我们有一张表:
CREATE TABLE erp_product_identity ( id BIGINT PRIMARY KEY, identity_code VARCHAR(50) UNIQUE, product_id BIGINT, warehouse_id BIGINT, update_time DATETIME );
我们现在有一个 list
,需要根据 identity_code
批量更新对应的 product_id
和 warehouse_id
。
三、MyBatis 批量更新写法(CASE WHEN)
以下是完整的 MyBatis XML 写法:
<update id="batchUpdateProductIdentityCase"> UPDATE erp_product_identity <set> product_id = CASE identity_code <foreach collection="list" item="item"> WHEN #{item.identityCode} THEN #{item.productId} </foreach> END, warehouse_id = CASE identity_code <foreach collection="list" item="item"> WHEN #{item.identityCode} THEN #{item.warehouseId} </foreach> END, update_time = NOW() </set> WHERE identity_code IN <foreach collection="list" item="item" open="(" separator="," close=")"> #{item.identityCode} </foreach> </update>
四、SQL 生成效果展示
当传入 3 条记录时:
list = [ { identityCode: 'A001', productId: 11, warehouseId: 101 }, { identityCode: 'A002', productId: 22, warehouseId: 102 }, { identityCode: 'A003', productId: 33, warehouseId: 103 } ];
最终生成的 SQL 如下:
UPDATE erp_product_identity SET product_id = CASE identity_code WHEN 'A001' THEN 11 WHEN 'A002' THEN 22 WHEN 'A003' THEN 33 END, warehouse_id = CASE identity_code WHEN 'A001' THEN 101 WHEN 'A002' THEN 102 WHEN 'A003' THEN 103 END, update_time = NOW() WHERE identity_code IN ('A001', 'A002', 'A003');
一次 SQL 更新三条数据。
效率远高于逐条执行!
五、WHERE IN 的作用(非常关键!)
有些人看到这行:
WHERE identity_code IN (...)
可能会问:这不是多余的吗?
其实它是 必须的!
没有这个条件,数据库会对整张表执行 UPDATE
,
未命中的记录的 CASE WHEN
结果是 NULL
,导致字段被更新成 NULL
,数据直接“报废”。 😱
所以必须加上 WHERE identity_code IN (...)
来限制更新范围。
六、性能对比
更新方式 | SQL 执行次数 | 性能(1000 条) | 备注 |
---|---|---|---|
循环单条更新 | 1000 次 | 🐢 慢 | 每次一条 SQL |
MyBatis 批量更新(CASE WHEN) | 1 次 | 🚀 快 | 一次 SQL 搞定 |
MyBatis 批量更新(foreach 多值) | 中等 | ⚡ 一般 | 取决于实现逻辑 |
推荐场景:
当你要批量更新几十到几百条数据(上千条以内)时,CASE WHEN
是最优解。
七、可维护性优化方案
为了可读性更高,可以把 CASE
部分封装成单独 SQL 片段:
<sql id="caseProductId"> product_id = CASE identity_code <foreach collection="list" item="item"> WHEN #{item.identityCode} THEN #{item.productId} </foreach> END </sql> <sql id="caseWarehouseId"> warehouse_id = CASE identity_code <foreach collection="list" item="item"> WHEN #{item.identityCode} THEN #{item.warehouseId} </foreach> END </sql> <update id="batchUpdateProductIdentityCase"> UPDATE erp_product_identity <set> <include refid="caseProductId"/> , <include refid="caseWarehouseId"/> , update_time = NOW() </set> WHERE identity_code IN <foreach collection="list" item="item" open="(" separator="," close=")"> #{item.identityCode} </foreach> </update>
这样结构更清晰、维护更方便。
八、使用建议与限制
项目 | 建议 / 限制 |
---|---|
identity_code | 必须是唯一键或主键 |
批量数量 | 推荐单次 ≤ 1000 条 |
SQL 长度 | MySQL 默认最大 1MB,可通过 max_allowed_packet 调整 |
时间字段 | 可以统一 update_time = NOW() |
数据库 | 适用于 MySQL、PostgreSQL、SQL Server |
九、总结
优点 | 缺点 |
---|---|
批量更新性能高 | SQL 长度可能受限 |
一次执行减少数据库压力 | 可读性稍弱 |
兼容 MyBatis 动态 SQL | 仅适合根据主键或唯一字段更新 |
结语
CASE WHEN
批量更新写法,是 MyBatis 开发中非常实用的一种性能优化技巧。
在日常项目中,当需要 根据不同条件批量更新不同字段值 时,它几乎是最优方案。
一条 SQL,解决多条更新,让你的系统更快、更稳、更优雅。
以上就是MyBatis使用CASE WHEN进行批量更新的高效写法的详细内容,更多关于MyBatis CASE WHEN批量更新的资料请关注脚本之家其它相关文章!