我最近做了一个应用程序,它从一个数据库(遗留数据库)中获取数据,并将其放入另一个数据库(新的开发数据库)。我发现令人困惑的是save
并不总是工作,但saveAndFlush
却工作。legacy
数据库位于一个事务select
中,而新数据库位于另一个事务deleteAll
和save
中。saveAndFlush
的应用程序非常非常慢,可以理解,但save
也好不了多少。然后我决定使用saveAll
,但为每个表创建一个巨大的列表的想法并不适合我。所以我试着像这样调用车库收藏:
productRepository.saveAll(productList);
productList.clear();
productList = null;
System.gc();
字符串
然后将jdbc.batch_size
添加到application.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
型
以前需要两个小时才能运行的程序现在只需5分钟-性能大幅提升。
现在我搞不清楚到底发生了什么。我读到的是“定期更新和清理会话”。但是delete
和saveAll
在一个事务中-因此对我来说没有意义。
所以要弄清楚为什么有两个问题:
1)为什么save
不能正常工作,而saveAndFlush
可以?
2)有50个表,每个表有20,000行,每个表创建一个列表,然后saveAll
,list被清除并建议进行垃圾收集。将上述内容添加到application.properties
中,与#1
方法相比,得到了一个非常快的应用程序。为什么?hibernate在做什么?是否定期更新和清除会话?
我认为发生的是第一层缓存保存了删除和插入,后来提交并希望刷新。显然我错了,或者至少不完全正确。
JPA batch inserts with Hibernate & Spring Data
1条答案
按热度按时间dm7nw8vv1#
保存和saveAndFlush的区别在于它们处理事务和持久化数据到数据库的方式。在保存的情况下,数据被保存到数据库,但可能不会立即刷新到数据库。实际的刷新可能在提交当前事务时或刷新持久性上下文时发生。另一方面,saveAndFlush会立即将数据持久化到数据库,并刷新更改。这意味着在方法调用返回之前,数据被保证保存在数据库中。
您在使用saveAll和垃圾收集沿着批处理大小配置时观察到的显著性能提升可归因于Hibernate的批处理机制。当您使用saveAll时,Hibernate通过将多个插入批量处理在一起来优化插入操作,从而减少数据库往返次数并提高性能。您配置的hibernate.jdbc.batch_size属性指定了在执行INSERT或UPDATE操作时,批量发送到数据库的语句数。这种批处理方法比为每个实体单独插入更有效,特别是在处理大量实体时。
通过显式清除productList并调用垃圾回收,您可以释放内存资源,这可以进一步提高性能,特别是在内存有限或处理大量数据的情况下。
总而言之,您观察到的性能改进是由于以下因素的组合:
使用saveAll支持批量处理,减少数据库往返次数。
配置hibernate.jdbc.batch_size属性可以将插入和更新操作一起批处理,从而优化它们。清空productList并调用垃圾回收,释放内存资源。
总的来说,这些优化在处理应用程序中的大型数据集时会带来更好的性能和更有效的资源使用。