BatchUpdateException问题:批量大小非1时触发MariaDB重复键错误
问题诊断与解决方案
问题背景
数据库迁移到Docker部署的MariaDB 10.11.4后,用继承BatchSqlUpdate的类做批量插入(批量大小100)时,带ON DUPLICATE KEY的INSERT语句触发唯一键重复错误;但把批量大小改成1就能正常执行。
依赖版本:mariadb-java-client 3.0.8、spring-jdbc 5.3.28、spring-data-jpa 2.5.7,无法升级spring-jdbc到6.x及以上。
原SQL语句存在语法错误,修正后如下:
INSERT INTO `table`(ldb, lid, scid, sid, valid) VALUES(?, ?, (SELECT id FROM cserver WHERE ldb=? AND lid=?), ?, 1) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), ldb=?, lid=?, scid=(SELECT id FROM cserver WHERE ldb=? AND lid=?), sid=VALUES(sid), valid=1;
注:原SQL漏写ON DUPLICATE KEY后的UPDATE关键字,且sid字段未指定赋值逻辑,这是语法硬伤。
可能的错误原因及排查方案
1. SQL语法错误导致批量执行异常
原SQL的语法错误会让数据库在批量解析时出现非预期行为,甚至把部分语句当成插入操作而非更新,直接触发唯一键冲突。先执行修正后的SQL,验证单条和批量(100)是否正常。
2. MariaDB 10.11.x批量写入与ON DUPLICATE KEY的兼容性问题
MariaDB 10.11.x对批量INSERT ... ON DUPLICATE KEY UPDATE的处理逻辑做了优化调整:
- 批量模式下,数据库会尝试先插入所有行,再统一处理重复项,这会导致中间触发唯一键约束错误(单条执行时是逐条处理,重复就更新,不会触发冲突)
- 解决方案:在JDBC连接URL中添加
rewriteBatchedStatements=false,强制驱动逐条执行批量语句(性能会下降,但能验证是否是批量优化导致的问题)
3. mariadb-java-client 3.x与Spring JDBC 5.3.x的适配问题
mariadb-java-client 3.x对JDBC批量操作的实现和2.x差异较大,而Spring JDBC 5.3.x的BatchSqlUpdate没完全适配这种变化:
- 尝试降级mariadb-java-client到2.7.7版本(该版本和Spring JDBC 5.3.x兼容性更好),再测试批量插入
- 检查
BatchSqlUpdate的配置:确保没开启useGeneratedKeys这类和批量插入冲突的选项,LAST_INSERT_ID(id)在批量场景下的返回逻辑和单条不一样,可能引发异常
4. Docker环境的数据库配置差异
Docker部署的MariaDB默认配置可能和原环境不同:
- 查看数据库的
sql_mode,确认是否开启了STRICT_TRANS_TABLES等严格模式,这类模式会放大批量操作的异常 - 核对表的唯一键约束,确保Docker环境下的表结构和原环境完全一致,避免重建表时约束定义出错
验证步骤
- 先用修正后的SQL执行单条插入/更新,确认业务逻辑没问题
- 给JDBC URL加上
rewriteBatchedStatements=false,保持批量100执行,看是否还报错 - 降级mariadb-java-client到2.7.7,重复批量测试
- 对比原数据库和Docker数据库的
sql_mode、表约束配置
内容的提问来源于stack exchange,提问作者Szonaldo
相关产品推荐
相关产品推荐

