MyBatis-Plus07:rewriteBatchedStatements 参数详解与批处理

一、什么是 rewriteBatchedStatements

这是 MySQL JDBC 驱动的一个连接参数。默认值为 false

当设置为 true 时,MySQL 驱动会将多条 INSERT 语句重写为一条批量 INSERT

sql 复制代码
-- rewriteBatchedStatements=false(默认)分开发送
INSERT INTO user (name, age) VALUES ('A', 1);
INSERT INTO user (name, age) VALUES ('B', 2);
INSERT INTO user (name, age) VALUES ('C', 3);

-- rewriteBatchedStatements=true 重写为一条
INSERT INTO user (name, age) VALUES ('A', 1), ('B', 2), ('C', 3);

1-1、配置方式

bash 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true

1-2、四种场景对比(10万条数据)

场景一:for 循环 10万次 save()rewriteBatchedStatements=false

java 复制代码
for (int i = 0; i < 100000; i++) {
    userMapper.save(new User("name" + i, i));
}

底层行为:

  • 每次 save() 都是一次独立的数据库连接请求(获取连接 → 发送SQL → 提交 → 释放连接)
  • 10万次 = 10万次网络往返(RTT)
  • 无任何批处理

性能: ❌❌❌ 极慢,约 60~120秒 以上


场景二:每1000条 saveBatch()rewriteBatchedStatements=false

java 复制代码
List<User> batch = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
    batch.add(new User("name" + i, i));
    if (batch.size() == 1000) {
        userService.saveBatch(batch); // MyBatis-Plus 默认 batchSize=1000
        batch.clear();
    }
}

底层行为:

  • MyBatis-Plus saveBatch() 内部使用了 JDBC 的 addBatch() / executeBatch()
  • 但由于 rewriteBatchedStatements=false,JDBC 虽然是批处理,MySQL 驱动仍然逐条发送给服务器
  • 相当于:将 1000 条 SQL 打包后依次发送,减少了获取连接的开销,但每条 SQL 仍单独传输
sql 复制代码
-- 实际发送给MySQL:
INSERT INTO user VALUES (...);  -- 第1条
INSERT INTO user VALUES (...);  -- 第2条
...(1000条分开发送)

性能: ✅ 比场景一好很多,约 5~15秒(减少了事务次数)

【注意】:网络请求过程中,可以发送的sql数量也是有限的!


场景三:每1000条 saveBatch()rewriteBatchedStatements=true

java 复制代码
List<User> batch = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
    batch.add(new User("name" + i, i));
    if (batch.size() == 1000) {
        userService.saveBatch(batch);
        batch.clear();
    }
}

底层行为:

  • saveBatch() 内部使用 addBatch() / executeBatch()
  • rewriteBatchedStatements=true 生效,MySQL 驱动将 1000 条重写为一条 SQL
sql 复制代码
INSERT INTO user (name, age) VALUES 
  ('name0', 0), ('name1', 1), ..., ('name999', 999);
  • 只需要 100次网络传输(10万/1000)
  • MySQL 服务器端一次性解析、一次性写入,效率极高

性能: ✅✅✅ 最快,约 1~3秒


二、性能对比汇总

场景 方式 rewriteBatchedStatements 网络IO次数 预估耗时(10万条)
场景一 for + save() false 10万次 60~120s ❌❌❌
场景二 saveBatch(1000) false 10万次(批量提交) 5~15s ✅
场景三 saveBatch(1000) true 100次 1~3s ✅✅✅

三、核心原理总结

rewriteBatchedStatements 生效的前提条件:

  1. JDBC 必须调用 addBatch() + executeBatch()

  2. MyBatis-Plus 的 saveBatch() 满足这个条件

  3. 逐条 save() 不满足,参数无效

saveBatch() 的作用:

  • 减少事务提交次数(场景二 vs 场景一)

rewriteBatchedStatements=true 的额外作用:

  • 将多条 INSERT 合并为一条,极大减少网络传输和服务器解析开销

最佳实践:saveBatch() + rewriteBatchedStatements=true,batchSize 推荐 500~1000。

相关推荐
ruleslol8 小时前
MyBatis-Plus08:代码生成
mybatis-plus
ruleslol9 小时前
MyBatis-Plus09:静态工具Db
mybatis-plus
树码小子13 小时前
Mybatis(17)Mybatis-Plus条件构造器(2)& 自定义 SQL
数据库·sql·mybatis-plus
ruleslol14 小时前
MyBatis-Plus10:逻辑删除
mybatis-plus
树码小子1 天前
Mybatis(16)Mybatis-Plus条件构造器(1)
数据库·mybatis-plus
树码小子3 天前
Mybatis(14)Mybatis-Plus入门 & 简单使用
java·mybatis-plus
ruleslol3 天前
MyBatis-Plus06:IService接口Lambda基本用法
mybatis-plus
ruleslol5 天前
MyBatis-Plus02: 常用注解
mybatis-plus
ruleslol6 天前
MyBatis-Plus05:IService接口基本用法
mybatis-plus