我们知道处理数据有三种思路:依次、批量、分页,对应方法如下
for 循环,依次使用 SQL 语句,频繁连接断开数据库 拼接成一条长 SQL 语句,仅连接断开一次数据库注意,若用 以 ; 分隔多条 SQL 语句发给数据库(需要在配置里添加 allowMultiQueries=true),这种处理虽然也可以算是某种程度上的“批量”,但其 SQL 语句并未在同一次提交中,因而本质上和依次处理没区别
选取哪种方法取决于你的数据量(记录数 × 字段数,也就是行数 × 列数)大小
当有一定的数据量后(千量级),依次处理非常慢,最好使用批量处理
而数据量过于庞大时(十万量级)如果还采取 进行批量处理,整个过程十分耗时,它处理时间和数据量的关系就像是倒过来的抛物线,如下图所示
通常需要进行折中,使用分页处理,根据笔者自己经验而言,将每次的数据量定在 12000 左右效果较好,不过这个具体要视情况而定

💬相关
博客文章《mybatis之foreach用法》
https://www.cnblogs.com/fnlingnzb-learner/p/10566452.html
博客文章《MyBatis批量插入几千条数据,请慎用foreach》
https://blog.csdn.net/SharingOfficer/article/details/121431154
以下给出一个示例场景
data_table,含有字段 id、field1 、 field2Data,含有属性 id、attr1 、 attr2下面给出依次操作和批量操作的 MyBatis 实现,而分页操作在 MyBatis 的实现和批量操作是一样的,不一样的地方在 Java 代码中
配置文件 application.properties 常见配置
serverTimezone:时区,如亚洲/上海时区 Asia/ShanghaiuseUnicode 和 characterEncoding :编码方式,如 true 和 utf8allowMultiQueries :是否支持”;"号分隔的多条 SQL 语句的执行,如 trueautoReconnect :是否超时重连(当一个连接的空闲时间超过 8 小时后,MySQL就会断开该连接),如 trueuseSSL:是否使用 SSL,如 truespring.datasource.url=jdbc:mysql://<域名或IP地址>:<端口号>/<数据库名>?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
对应 SQL 的 SELECT 语句
对应生成的 SQL 语句
SELECT * FROM `data_table`
WHERE `id` = ?
SELECT * FROM `data_table`
WHERE `id` IN (?,?,?)
对应 SQL 的 INSERT INTO 语句
注意,若设置了主键,且表中存在相同主键的数据,则无法插入
INSERT INTO `data_table`(`id`,`field1`,`field2`)VALUES (#{id},#{attr1},#{attr2}) INSERT INTO `data_table`(`id`,`field1`,`field2`)VALUES(#{item.id},#{item.attr1},#{item.attr2})
对应生成的 SQL 语句
INSERT INTO `data_table`(`id`,`field1`,`field2`)
VALUES (?,?,?)
INSERT INTO `data_table`(`id`,`field1`,`field2`)
VALUES(?,?,?),(?,?,?),(?,?,?)
对应 SQL 的 UPDATE 语句
配合 SQL 中的 WHEN...THEN... 语句,这相当于其他编程语言中的 switch 语句
UPDATE `data_table`SET `field1` = #{attr1}, `field2` = #{attr2}WHERE `id` = #{id}
UPDATE `data_table`WHEN `id` = #{item.id} THEN #{item.attr1} WHEN `id` = #{item.id} THEN #{item.attr2} WHERE `id` IN#{item.id}
对应生成的 SQL 语句
UPDATE `data_table`
SET `field1` = ?, `field2` = ?
WHERE `id` = ?
UPDATE `data_table`
SET `field1` =CASEWHEN `id` = ? THEN ?WHEN `id` = ? THEN ?WHEN `id` = ? THEN ?END,`field2` =CASEWHEN `id` = ? THEN ?WHEN `id` = ? THEN ?WHEN `id` = ? THEN ?END
WHERE`id` IN (?,?,?)
仅 MySQL 支持,且需要设置主键
对应 MySQL 的REPLACE INTO 或 INSERT INTO... ON DUPLICATE KEY UPDATE ... 的语句
二者均是根据主键判断表中是否含有重复的数据,若无就直接插入,若有,前者是先删再插,后者是更新
从底层执行效率上来讲,REPLACE INTO 效率更高,但部分场景并不适合,需慎用
当然,你也可以先 DELETE 再 INSERT INTO 达到同样的效果,但显然没有上面二者高效
💬相关
文章《慎用mysql replace语句》
https://developer.aliyun.com/article/627744
由于 REPLACE INTO 和 INSERT INTO 的 MyBatis 实现是几乎一样的,此处就不再赘述了
INSERT INTO `data_table` (`id`,`field1`,`field2`)VALUES (#{id},#{attr1},#{attr2})ON DUPLICATE KEY UPDATE`id` = VALUES(`id`),`field1` = VALUES(`field1`),`field2` = VALUES(`field2`)
INSERT INTO `data_table` (`id`,`field1`,`field2`)VALUES(#{item.id},#{item.attr1},#{item.attr2}) ON DUPLICATE KEY UPDATE`id` = VALUES(`id`),`field1` = VALUES(`field1`),`field2` = VALUES(`field2`)
对应生成的 SQL 语句
INSERT INTO `data_table` (`id`,`field1`,`field2`)
VALUES (?,?,?)
ON DUPLICATE KEY UPDATE`id` = VALUES(`id`),`field1` = VALUES(`field1`),`field2` = VALUES(`field2`)
INSERT INTO `data_table`(`id`,`field1`,`field2`)
VALUES (?,?,?),(?,?,?),(?,?,?)
ON DUPLICATE KEY UPDATE`id` = VALUES(`id`),`field1` = VALUES(`field1`),`field2` = VALUES(`field2`)
对应 SQL 的 DELETE 语句
DELETE FROM `data_table` WHERE `id` = #{id}
DELETE FROM `data_table`WHERE `id` IN#{item}
对应生成的 SQL 语句
DELETE FROM `data_table` WHERE `id` = ?
DELETE FROM `data_table`
WHERE `id` IN (?,?,?)
对应 SQL 的 TRUNCATE 语句
TRUNCATE TABLE `data_table`
对应生成的 SQL 语句
TRUNCATE TABLE `data_table`
💬相关
看完本文后可以进一步阅读博客文章《基于SpringBoot的数据迁移模板》
https://blog.csdn.net/weixin_42077074/article/details/128868655