rewritebatchedstatements=true未生效最常见原因是url漏配或拼写错误、驱动版本过低(需≥5.1.13,推荐8.0.29+)、误用statement而非preparedstatement;此外max_allowed_packet限制、null字段或时间类型不兼容也会导致重写失败。

rewriteBatchedStatements=true 为什么没生效
最常见的情况是:你加了参数,但批量插入速度几乎没变。这不是配置写错了,而是它根本没被驱动识别或触发。关键原因有三个:
• 连接 URL 里漏写了 rewriteBatchedStatements=true,或者拼写错误(比如写成 rewriteBatchStatement 少了个 s)
• 驱动版本太低 —— 必须 ≥ 5.1.13,但更推荐用 8.0.29+,否则对 LocalDateTime、null 字段重写会抛 SQLSyntaxErrorException
• 用的是 Statement 而不是 PreparedStatement —— 这个参数只对后者生效,MyBatis-Plus 的 saveBatch 是 OK 的,但手写 JDBC 时如果用了 conn.createStatement() 就白配了
INSERT 批量重写失败的典型报错
开启后反而报错,基本就两类:
• Packets larger than max_allowed_packet bytes:驱动把 1000 条 INSERT 合成一条大 SQL,超了 MySQL 的 max_allowed_packet(默认 4MB)。解决办法不是缩小 batch size,而是同步调大 MySQL 配置:SET GLOBAL max_allowed_packet = 67108864;(64MB),并写入 my.cnf
• java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax:通常因为字段含 null 值或时间类型不兼容(如 LocalDateTime 在老驱动里转成字符串失败)。建议升级驱动到 8.0.33,并在实体类上显式标注 @TableField(fill = FieldFill.INSERT) 避免空值传入
MyBatis-Plus saveBatch 怎么配合 rewriteBatchedStatements
saveBatch 本身不决定是否重写,它只是触发 addBatch() + executeBatch(),真正起作用的是驱动层。所以要注意:
• 不要依赖 batchSize 参数来“控制重写效果”——设成 1000 或 100,只要开了 rewriteBatchedStatements=true,驱动都会尽力合并(实际合并条数受 max_allowed_packet 和字段长度限制)
• 如果用了逻辑删除或自动填充(如 create_time),确保这些字段在数据库允许 NULL 或有默认值,否则重写后的多值 INSERT 会因某一行字段缺失直接失败
• 日志里看到 INSERT INTO ... VALUES (?, ?), (?, ?), ... 才算真生效;如果还是每行一个 INSERT,说明连接池(如 HikariCP)可能缓存了旧连接,重启应用或清空连接池再测
它对 UPDATE/DELETE 也有效,但有隐藏限制
文档说支持 INSERT/UPDATE/DELETE,但实测中:
• UPDATE 重写仅限单表、无子查询、SET 子句字段顺序必须严格一致(否则驱动无法合并)
• DELETE 只支持 WHERE pk IN (?,?,?) 这种形式,且必须用 PreparedStatement 绑定参数;写成 WHERE id = ? OR id = ? 就不会重写
• 所有重写都绕不开 max_allowed_packet,尤其是批量 UPDATE 涉及长文本字段时,很容易触顶报错,建议压测时用真实数据长度做边界验证
max_allowed_packet 还卡在 4MB。











