bigywater.tech
Spring · 163

JdbcClient、JdbcTemplate、JPA:单条与批量写入的吞吐

写 MySQL 用 JdbcTemplate、JdbcClient 还是 JPA 更快?批量写入到底能快多少?rewriteBatchedStatements 与主键策略有什么影响?这篇在同一台机器上把九种写法各跑两轮,波动大的地方照实写出来。

10 倍以上
加 rewriteBatchedStatements=true 后 JdbcTemplate.batchUpdate 约 25 万行/秒,是同一事务里逐行(约 2.4 万行/秒)的 10 倍以上
IDENTITY
JPA saveAll 用 IDENTITY 主键时仍约 2.1 万行/秒,没有批量效果;换成 AUTO(序列表)后 6.5 万到 8.6 万行/秒
944 对 8652
同一个「JdbcTemplate 逐行自动提交」模式两轮的行/秒,波动 9 倍,自动提交的数字只能看量级

不加参数

实测 · 本机执行输出
  1 JdbcTemplate.update 逐行,每行自动提交(n=2000):两轮 231 ms / 2119 ms,即 8652 / 944 行/秒
  2 JdbcClient.sql().params().update() 逐行,每行自动提交(n=2000):两轮 260 ms / 1230 ms,即 7679 / 1626 行/秒
  3 JPA repository.save 逐行,每次 save 一个事务(IDENTITY)(n=2000):两轮 566 ms / 818 ms,即 3531 / 2445 行/秒
  4 JdbcTemplate.update 逐行,同一个事务(n=20000):两轮 855 ms / 2630 ms,即 23396 / 7604 行/秒
  5 JdbcClient 逐行,同一个事务(n=20000):两轮 818 ms / 983 ms,即 24443 / 20336 行/秒
  6 JPA save 逐行,同一个事务(IDENTITY)(n=20000):两轮 1083 ms / 1178 ms,即 18468 / 16979 行/秒
  7 JdbcTemplate.batchUpdate(每批 1000),同一个事务(n=20000):两轮 721 ms / 790 ms,即 27758 / 25332 行/秒
  8 JPA saveAll(IDENTITY,hibernate.jdbc.batch_size=1000),同一个事务(n=20000):两轮 994 ms / 1000 ms,即 20127 / 19992 行/秒
  9 JPA saveAll(AUTO 序列,hibernate.jdbc.batch_size=1000),同一个事务(n=20000):两轮 1538 ms / 964 ms,即 13006 / 20751 行/秒

批量写入只比逐行快一点;自动提交逐行波动极大;JdbcTemplate 与 JdbcClient 无法区分。

加 rewrite

实测 · 本机执行输出
  1 JdbcTemplate.update 逐行,每行自动提交(n=2000):两轮 218 ms / 237 ms,即 9178 / 8450 行/秒
  2 JdbcClient.sql().params().update() 逐行,每行自动提交(n=2000):两轮 282 ms / 206 ms,即 7100 / 9723 行/秒
  3 JPA repository.save 逐行,每次 save 一个事务(IDENTITY)(n=2000):两轮 845 ms / 448 ms,即 2367 / 4462 行/秒
  4 JdbcTemplate.update 逐行,同一个事务(n=20000):两轮 832 ms / 821 ms,即 24043 / 24375 行/秒
  5 JdbcClient 逐行,同一个事务(n=20000):两轮 950 ms / 930 ms,即 21054 / 21496 行/秒
  6 JPA save 逐行,同一个事务(IDENTITY)(n=20000):两轮 1103 ms / 1036 ms,即 18137 / 19302 行/秒
  7 JdbcTemplate.batchUpdate(每批 1000),同一个事务(n=20000):两轮 78 ms / 82 ms,即 257010 / 242633 行/秒
  8 JPA saveAll(IDENTITY,hibernate.jdbc.batch_size=1000),同一个事务(n=20000):两轮 892 ms / 947 ms,即 22421 / 21120 行/秒
  9 JPA saveAll(AUTO 序列,hibernate.jdbc.batch_size=1000),同一个事务(n=20000):两轮 233 ms / 306 ms,即 85714 / 65377 行/秒

batchUpdate 与 AUTO 主键的 saveAll 大幅加速;IDENTITY 主键仍不批量。

分步演示

写入
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动(Spring Boot 4.0.8,Spring Framework 7.0.9,Hibernate 7.2,MySQL 是本机自己起的实例;单行自动提交模式插入 2000 行,同一个事务里的模式插入 20000 行;每个模式先 truncate 再计时,一轮内取 3 次的中位数,每种 URL 各跑 2 轮;hibernate.jdbc.batch_size=1000 与 order_inserts=true;预热 300 行)
    • 没有验证:PostgreSQL 与其他数据库;更大的行宽、索引数量与表数据量;多线程并发写入;MySQL 的 innodb_flush_log_at_trx_commit 等刷盘参数对自动提交模式的影响(自动提交波动较大,猜测与刷盘有关,没有验证);Hibernate 的 JDBC 批量与 StatelessSession;JdbcClient 的批量用法;跨机器网络延迟下的差异
    京ICP备2026067502号-1京公网安备11010502063487号