网站首页 > 技术文章 正文
我们在使用 Mybatis 框架进行实现数据库操作的时候,通常会遇到一些需要进行批量修改的方式,不同的方式可适用不同的场景,也会出现一些优缺点。本文常见的 Mybatis 批量修改方法并进行总结:
1. 循环修改
通过 Java 循环调用单个 update 语句实现批量修改,不考虑性能,最简单,最偷懒的方式。
Mapper 接口:
void updateUser(User user);
XML 映射:
<update id="updateUser">
UPDATE user
SET name = #{name}, age = #{age}
WHERE id = #{id}
</update>
Service中调用:
for (User user : userList) {
userMapper.updateUser(user);
}
特点:
- 实现简单,易于理解和维护
- 性能差(需要多次进行数据库连接和交互)
- 适用于数据量极小的场景
2. 使用 MyBatis 的 foreach 标签构建批量修改SQL
通过 foreach 标签动态生成批量更新语句。
Mapper 接口:
void batchUpdate(@Param("list") List<User> userList);
XML 映射:
<update id="batchUpdate">
UPDATE user
SET name = CASE
<foreach collection="list" item="item" index="index">
WHEN id = #{item.id} THEN #{item.name}
</foreach>
END,
age = CASE
<foreach collection="list" item="item" index="index">
WHEN id = #{item.id} THEN #{item.age}
</foreach>
END
WHERE id IN
<foreach collection="list" item="item" separator="," open="(" close=")">
#{item.id}
</foreach>
</update>
特点:
- 一次数据库连接完成批量操作
- SQL 语句长度随数据量增长,有可能超过数据库限制
- 适用于中等数据量(建议不超过 1000 条)
3. 多条 SQL 语句批量执行
在一条 SQL 中包含多个 update 语句,用分号分隔。 Mapper 接口:
void batchUpdateMultiSQL(@Param("list") List<User> userList);
XML 映射:
<update id="batchUpdateMultiSQL">
<foreach collection="list" item="item" separator=";">
UPDATE user
SET name = #{item.name}, age = #{item.age}
WHERE id = #{item.id}
</foreach>
</update>
注意:进行这个操作的时候,需要在数据库连接 URL 中添加 allowMultiQueries=true 参数(以 MySQL 为例)。
特点:
- 实现简单,SQL 语句清晰
- 同样存在 SQL 长度限制问题
- 部分数据库可能不支持(需数据库特性支持)
4. 使用 BatchExecutor(MyBatis 批量执行器)
配置 MyBatis 执行器为 BATCH 模式,主要作用是累积所有Sql语句进行一次性执行的操作。
实现方式:
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper userMapper = session.getMapper(UserMapper.class);
for (User user : userList) {
userMapper.updateUser(user);
}
session.commit();
session.close();
特点:
- MyBatis 内部优化的批量处理方式
- 减少网络交互和事务提交次数
- 内存占用可能较高(需注意批量大小)
- 适用于大数据量批量操作
5. 使用数据库特定的批量更新语法
某些数据库提供了专有的批量更新语法,如 PostgreSQL 的 UPDATE ... FROM 语法。
PostgreSQL 示例:
<update id="batchUpdatePostgreSQL">
UPDATE user u
SET name = c.name, age = c.age
FROM (
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.id}, #{item.name}, #{item.age})
</foreach>
) AS c(id, name, age)
WHERE u.id = c.id
</update>
特点:
- 性能好,充分利用数据库特性
- 数据库兼容性差,移植性低
- 适用于固定使用特定数据库的场景
方法比较总结
方法 | 优点 | 缺点 | 适用场景 |
循环修改 | 简单直观,易于调试 | 性能差,多次交互 | 数据量极小(<10 条) |
foreach 构建 CASE 语句 | 一次交互,兼容性好 | SQL 长度有限制 | 中等数据量(<1000 条) |
多条 SQL 语句批量执行 | 实现简单,SQL 清晰 | 需数据库支持,有长度限制 | 数据量较小,且数据库支持 |
BatchExecutor | 性能好,MyBatis 原生支持 | 内存占用高,需手动管理会话 | 大数据量批量操作 |
数据库特定语法 | 性能最优,利用数据库特性 | 兼容性差,移植性低 | 固定数据库,追求极致性能 |
个人建议
- 数据量小时(<100 条),优先考虑 foreach 构建 CASE 语句。
- 数据量大时(>1000 条),建议使用 BatchExecutor 并分批处理(每批 500-1000 条)。
- 考虑数据库特性,如果项目固定使用某一数据库,可采用其专有的批量语法。
- 避免循环单次修改,除非数据量极小且对性能无要求。
最主要一点,选择合适的批量修改方式需综合考虑数据量大小、数据库类型、性能要求和代码可维护性等因素。
猜你喜欢
- 2025-09-04 高效使用Java构建工具,Maven篇|云效工程师指北
- 2025-09-04 MyBatis源码解析_mybatis3源码深度解析
- 2025-09-04 如何一眼定位SQL的代码来源:一款SQL染色标记的简易MyBatis插件
- 2025-09-04 使用模板也可以有自己的style——模板方法模式
- 2025-06-13 Mybatis一级缓存和二级缓存原理区别(图文详解)
- 2025-06-13 MyBatis的10种用法(mybatis语句)
- 2025-06-13 MyBatis 插件原理与实战(mybatis插件执行顺序)
- 2025-06-13 MyBatis-Flex一个优雅的 MyBatis增强框架
- 2025-06-13 MyBatis动态SQL的5种高级玩法,90%的人只用过3种
- 2025-06-13 MyBatis-Plus码之重器 lambda 表达式使用指南,开发效率瞬间提升80%
- 09-12Pandas之十二速查手册(推荐打印)_pandas速查手册中文版
- 09-12C# Token 浅析_.net core token
- 09-12Spring源码|Spring实例Bean的方法
- 09-12Metasploitable2笔记(漏洞利用与加固)
- 09-12.NET Core 中推荐使用的10大优秀库,你用到过几个?
- 09-12C# RulesEngine 规则引擎:从入门到看懵
- 09-12World Insights: Japan's plot to discharge Fukushima nuclear-contaminated wastewater into sea
- 09-12用 Python 守护你的 API:从入门到实践的安全监测指南
- 最近发表
-
- Pandas之十二速查手册(推荐打印)_pandas速查手册中文版
- C# Token 浅析_.net core token
- Spring源码|Spring实例Bean的方法
- Metasploitable2笔记(漏洞利用与加固)
- .NET Core 中推荐使用的10大优秀库,你用到过几个?
- C# RulesEngine 规则引擎:从入门到看懵
- World Insights: Japan's plot to discharge Fukushima nuclear-contaminated wastewater into sea
- 用 Python 守护你的 API:从入门到实践的安全监测指南
- JNI 跨线程调用时局部引用的陷阱_java跨进程调用
- Android Framework 输入子系统 (10)Input命令解读
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)