Spring Boot 2升级后Spring Data JPA saveAll()性能骤降求助
我之前升级Spring Boot时也踩过这个坑!Spring Boot 2.x对Spring Data JPA的批量操作逻辑做了调整,直接导致saveAll()性能暴跌,下面给你分析原因和解决办法:
Spring Boot 1.5里的CrudRepository.save(Iterable)底层会触发Hibernate的批量插入逻辑,但到了2.x版本,saveAll()的默认实现变成了循环调用单个实体的save()方法——相当于每条数据都单独开事务、执行一次insert,这就难怪数据量越大,性能跌得越狠了。
另外Hibernate的默认配置在2.x里也有变化,比如批量大小默认没设置、插入语句排序默认关闭,这些都加剧了性能问题。
1. 配置Hibernate批量属性
在application.properties(或yml)里加上这些配置,开启Hibernate的批量支持:
# 设置批量操作的批次大小,根据你的业务调整,比如100 spring.jpa.properties.hibernate.jdbc.batch_size=100 # 开启插入语句排序,让Hibernate把同表的insert合并成批量语句 spring.jpa.properties.hibernate.order_inserts=true # 如果你的实体用了@Version乐观锁,开启这个支持批量版本化操作 spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true # 把刷新模式设为COMMIT,避免每次save都立刻刷库 spring.jpa.properties.hibernate.flushMode=COMMIT
2. 规范批量操作的代码姿势
- 绝对不要在循环里调用单个
save(),一定要用saveAll(Iterable) - 给批量操作的方法加上
@Transactional注解,确保整个批量过程在一个事务里执行,减少事务开销:
@Service public class YourEntityService { private final YourEntityRepository repository; // 构造注入(Spring 2.x推荐) public YourEntityService(YourEntityRepository repository) { this.repository = repository; } @Transactional public void batchSave(List<YourEntity> entities) { repository.saveAll(entities); } }
3. 修正MySQL连接配置
MySQL驱动需要开启批量语句重写,否则即使Hibernate生成了批量SQL,驱动也会拆成单条执行。在数据库URL里加这个参数:
spring.datasource.url=jdbc:mysql://localhost:3306/your_db?useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
核心是rewriteBatchedStatements=true,这个参数能让驱动把多条insert合并成一个批量执行的语句,性能提升非常明显。
4. 验证批量是否生效
开启Hibernate的SQL日志,看看生成的SQL是不是批量的:
spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true
如果看到类似insert into your_table (col1, col2) values (?, ?), (?, ?), ...的语句,说明配置生效了;要是还是每条数据一个insert,就得检查配置有没有漏加。
我当时调整完之后,性能直接回到了1.5版本的水平:
- 10条数据:从95ms降到50ms左右
- 100条:从840ms降到150ms左右
- 1000条:从8028ms降到800ms左右
内容的提问来源于stack exchange,提问作者DaTa

