MyBatis使用CASE WHEN进行批量更新的高效写法

 更新时间:2025年10月10日 09:03:47   作者:一勺菠萝丶  
当我们使用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_idwarehouse_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批量更新的资料请关注脚本之家其它相关文章!

相关文章

  • 详解Java 集合系列(三)—— LinkedList

    详解Java 集合系列(三)—— LinkedList

    这篇文章主要介绍了Java 集合系列(三)—— LinkedList,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • Springboot应用中@EntityScan和@EnableJpaRepositories的使用详解

    Springboot应用中@EntityScan和@EnableJpaRepositories的使用详解

    在Spring Boot中,若Entity和Repository不在主包内,需通过@EntityScan和@EnableJpaRepositories指定扫描路径,注意basePackages需完整覆盖,避免重复注册或Bean缺失错误
    2025-08-08
  • Java的垃圾强制回收实例分析

    Java的垃圾强制回收实例分析

    这篇文章主要介绍了Java的垃圾强制回收,结合实例形式分析了java垃圾强制回收的相关原理及实现方法,需要的朋友可以参考下
    2019-08-08
  • JavaGUI界面实现页面跳转方法

    JavaGUI界面实现页面跳转方法

    这篇文章主要给大家介绍了关于JavaGUI界面实现页面跳转的相关资料, GUI是指图形用户界面,指采用图形方式显示的计算机操作用户界面,需要的朋友可以参考下
    2023-07-07
  • SpringBoot项目中@Test不出现可点击运行的按钮问题

    SpringBoot项目中@Test不出现可点击运行的按钮问题

    这篇文章主要介绍了SpringBoot项目中@Test不出现可点击运行的按钮问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Springboot2整合knife4j过程解析

    Springboot2整合knife4j过程解析

    这篇文章主要介绍了Springboot2整合knife4j过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 一篇文章带你搞懂Java restful 接口开发

    一篇文章带你搞懂Java restful 接口开发

    这篇文章主要介绍了Java restful 接口开发的几种方式(HTTPS),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-10-10
  • Java项目--家庭收支记录程序

    Java项目--家庭收支记录程序

    本文主要介绍Java基础阶段的一个小项目——家庭收支记录程序(附完整源代码),本项目所用到的主要知识点:基本语法、数组和方法。本项目并不难,主要是对Java初学者的基础综合运用的训练及检验
    2021-07-07
  • 详解SpringCloudGateway内存泄漏问题

    详解SpringCloudGateway内存泄漏问题

    这篇文章主要介绍了详解SpringCloudGateway内存泄漏问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Java编程实现快速排序及优化代码详解

    Java编程实现快速排序及优化代码详解

    这篇文章主要介绍了Java编程实现快速排序及优化代码详解,具有一定借鉴价值,需要的朋友可以了解下。
    2017-12-12

最新评论