问题描述
使用Spring Data JPA存储库将数据保存到数据库时,我遇到了一个问题。
我的情况:我正在使用一个循环来逐一收集和保存数据。收集所有数据需要花费大量时间。因此,我想将每个记录的数据立即保存到表的数据库中。我正在使用saveAndFlush
方法,但是数据没有立即保存到表中。
我等不及要收集所有数据,因为可能需要一整天才能收集所有数据。
解决方法
也许您的方法可能带有@Transactional批注,并且可能等待所有实体就绪以一次保存所有实体。
JPA有一个“ saveAll”方法,您可以一次保存整个集合,我建议您使用此方法,这样就不必为每个实体发送单独的请求,而不必增加数据库工作量和网络带宽。 >
,我不确定100%确定如何测试数据是否不会立即写入数据库,但是我猜您正在使用单独的数据库连接进行检查。
这可能意味着您的数据已写入数据库,但未提交,因此对于其他会话不可见。
确保事务范围仅在用于编写的循环内 。
为此,当对@Transactional
的调用在事务内时,包含for循环的方法不应具有save
批注或事务中包含的任何其他方式。 saveAndFlush
是不必要的,因为事务已提交,无论如何这将触发刷新。
如果对save
的调用是与数据库的唯一交互,Spring实际上会自动将其包装在事务中,因为存储库开箱即用@Transactional
进行了注释。否则,您需要使用the transaction support of Spring来实现。
我认为一次保存每条记录不是一个好主意,尽管有可能。
刷新是将持久性上下文的状态与基础数据库进行同步的过程。如果发生预期的事情,则该事务将回滚,不保留任何数据。
天真的解决方案是使用单独的事务( Propagation.REQUIRES_NEW )。请注意,这会产生巨大的性能消耗。因此,我个人建议在一个事务(批处理)中保存许多记录。 https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#batch
因此,无论您在哪里使用循环,请确保它在与上一个循环不同的事务中运行。
OR
如果您使用的是 spring-data-jpa ,则有更简单的方法来批量处理实体。您只需要完成两件事即可:
- 在属性文件中,设置选项
spring.jpa.properties.hibernate.jdbc.batch_size=any_size
- 将回购的
saveAll()
方法与准备插入的实体列表一起使用。 在此处查看更多https://dzone.com/articles/50-best-performance-practices-for-hibernate-5-amp
检查以下图像,了解 REQUIRES_NEW 和 REQUIRED 的工作方式:
AND REQUIRES_NEW