JPA saveAll更快,更可靠,然后通过大插入量保存

Dre*_*208 6 hibernate jpa-2.0 spring-data-jpa

我最近制作了一个应用程序,该应用程序从一个数据库(旧版)中获取数据,然后将其放入另一个数据库中(新的开发数据库)。我发现困惑save并不总是奏效,而是奏效saveAndFlush了。该legacy数据库是在一个事务select和新的数据库是另一个deleteAllsave

该应用程序运行非常缓慢saveAndFlush且易于理解,但save效果并不好。然后我决定使用,saveAll但是为每个表创建一个巨大列表的想法对我来说并不成立。所以我试图像这样调用车库收集:

 productRepository.saveAll(productList);

 productList.clear();
 productList = null;
 System.gc();
Run Code Online (Sandbox Code Playgroud)

然后我添加jdbc.batch_sizeapplication.properties

logging.level.org.hibernate.SQL=info
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

spring.jpa.generate-ddl = true

spring.jpa.properties.hibernate.jdbc.batch_size = 20
spring.jpa.properties.hibernate.order_inserts = true
spring.jpa.properties.hibernate.order_updates = true
spring.jpa.properties.hibernate.jdbc.batch_versioned_data = true
Run Code Online (Sandbox Code Playgroud)

之前需要花两个小时才能运行,现在只有5分钟-巨大的性能提升。

现在我很困惑发生了什么。我读到的是“定期更新和关闭会话”。但是deletesaveAll是一次交易-因此对我来说这没有意义。

因此要弄清楚为什么有两个问题:

1)为什么不save总是有效但saveAndFlush会起作用?

2)有50个表,每个表有20,000行,每个表创建一个列表,然后saveAll清除该列表并建议进行垃圾回收。application.properties与方法相比,将上面的内容添加到导致应用程序极快#1。为什么?冬眠在做什么?是否定期更新和清除会话?

我认为正在发生的事情是第一层缓存保留了删除和插入操作,然后提交并希望将其刷新。显然我是错误的,或者至少不是完全正确的。

具有Hibernate和Spring数据的JPA批处理插入

小智 -1

savesaveAndFlush之间的区别在于它们处理事务和将数据保存到数据库的方式。在保存的情况下,数据会保存到数据库,但可能不会立即刷新到数据库。实际的刷新可能稍后在提交当前事务时或刷新持久性上下文时发生。另一方面,saveAndFlush立即将数据保存到数据库并刷新更改。这意味着在方法调用返回之前数据保证保存在数据库中。

您在使用saveAll和垃圾收集以及批处理大小配置时观察到的显着性能提升可归因于 Hibernate 的批处理机制。当您使用saveAll时,Hibernate 通过将多个插入一起批处理来优化插入操作,减少数据库往返次数并提高性能。您配置的hibernate.jdbc.batch_size属性指定执行INSERT 或 UPDATE操作时将批量发送到数据库的语句数。这种批处理方法比每个实体的单独插入更有效,特别是在处理大量实体时。

通过显式清除productList并调用垃圾回收,您可以释放内存资源,这可以进一步提高性能,特别是在内存有限或处理大量数据的情况下。

总之,您观察到的性能改进是多种因素共同作用的结果:

使用saveAll可以进行批处理,从而减少数据库往返次数。

配置hibernate.jdbc.batch_size 属性可以通过将插入和更新操作批处理在一起来优化它们。清除productList并调用垃圾回收可以释放内存资源。

总的来说,在应用程序中处理大型数据集时,这些优化可以提高性能并更有效地利用资源。