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批量更新的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈SpringBoot实现自动装配的方法原理

    浅谈SpringBoot实现自动装配的方法原理

    SpringBoot的自动装配是它的一大特点,可以大大提高开发效率,减少重复性代码的编写。本文将详细讲解SpringBoot如何实现自动装配,需要的朋友可以参考下
    2023-05-05
  • 使用SpringCache操作Redis缓存数据的示例代码

    使用SpringCache操作Redis缓存数据的示例代码

    SpringCache是一个框架,实现了基于注解的缓存功能,只需要简单的加一个注解,就能实现缓存功能,本文给大家介绍了如何使用SpringCache操作Redis缓存数据,文中有相关的代码示例供大家参考,需要的朋友可以参考下
    2024-01-01
  • Spring实战之使用TransactionProxyFactoryBean实现声明式事务操作示例

    Spring实战之使用TransactionProxyFactoryBean实现声明式事务操作示例

    这篇文章主要介绍了Spring实战之使用TransactionProxyFactoryBean实现声明式事务操作,结合实例形式分析了spring使用TransactionProxyFactoryBean实现声明式事务相关配置、接口设置与使用技巧,需要的朋友可以参考下
    2020-01-01
  • jedispool连redis高并发卡死的问题

    jedispool连redis高并发卡死的问题

    本篇文章主要介绍了jedispool连redis高并发卡死的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Java中Elasticsearch的核心概念详解

    Java中Elasticsearch的核心概念详解

    这篇文章主要介绍了Java中Elasticsearch的核心概念详解,Elasticsearch 是一个分布式、免费和开放的搜索和分析引擎,适用于所有类型的数据,包括文本、数字、地理空间、结构化和非结构化数据,需要的朋友可以参考下
    2023-07-07
  • 一文带你了解微服务架构中的"发件箱模式"

    一文带你了解微服务架构中的"发件箱模式"

    微服务架构如今非常的流行,这个架构下可能经常会遇到“双写”的场景。本文就和大家分享一个“发件箱模式”, 感兴趣的小伙伴可以了解一下
    2023-01-01
  • java根据当前时间获取yyyy-MM-dd HH:mm:ss标准格式的时间代码示例

    java根据当前时间获取yyyy-MM-dd HH:mm:ss标准格式的时间代码示例

    在Java中可以使用java.time包中的LocalDateTime类和DateTimeFormatter类来获取并格式化当前时间为yyyy-MM-dd HH:mm:ss的格式,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-10-10
  • Java实现锁定某个变量的几种方式示例详解

    Java实现锁定某个变量的几种方式示例详解

    这篇文章主要为大家介绍了Java实现锁某个变量的几种方式示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • java byte与base64的互转的实现示例

    java byte与base64的互转的实现示例

    在项目开发中经常用到,比如前端上送文件流(byte[])到后台并转成文件,本文主要介绍了java byte与base64的互转的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-02-02
  • java截取图片示例

    java截取图片示例

    这篇文章主要介绍了java截取图片示例,把代码中的图片路径改成自己的图片,运行就可以看到效果了,需要的朋友可以参考下
    2014-03-03

最新评论