我想从PostgreSQL 11.2流式传输结果,而不是一次将所有结果读到内存中。我使用最新的稳定版SpringBoot 2.1.4.RELEASE。
我阅读了文章如何在MySQL中进行操作。 http://knes1.github.io/blog/2015/2015-10-19-streaming-mysql-results-using-java8-streams-and-spring-data.html 我还阅读了文章如何在PostgreSQL中做到这一点: Java 8 JPA Repository Stream row-by-row in Postgresql
我有这样的存储库:
public interface ProductRepository extends JpaRepository<Product, UUID> {
@Query("SELECT p from Product p")
@QueryHints(value = @QueryHint(name = HINT_FETCH_SIZE, value = "50"))
Stream<Product> streamAll();
}
比我那样使用流:
productRepository.streamAll().forEach(product -> export(product));
为了简化示例,“ export”方法完全为空。
当我调用该方法时,我会看到休眠查询
Hibernate: select product0_.id as id1_0_, product0_.created as created2_0_, product0_.description as descript3_0_, product0_.name as name4_0_, product0_.product_type_id as product_5_0_ from products product0_ order by product0_.id
,一段时间后,我遇到了OutOfMemoryError。 查询提示没有帮助。
如何使用Spring Boot存储库(甚至EntityManager)读取数据以及如何以最佳方式从数据库加载行。 我知道我可以进行分页,但是正如在撰写文章中所述,这不是最佳方法。
答案 0 :(得分:1)
目前使用spring检索所有数据,并且Stream仅应用于已在内存中的数据。
如果您查看org.springframework.data.jpa.provider.PersistenceProvider
的来源,似乎它使用ScrollableResults
来流式传输数据。
通常ScrollableResults
检索内存中的所有数据。
您可以使用MySql数据库here找到有趣的完整分析,但对于Postgres数据库也可以使用相同的分析。
因此,如果您认为使用的解决方案实际上不需要使用大量内存,那么它也会这样做,因为基础实现未使用最佳实现。
答案 1 :(得分:0)
我面临着完全相同的问题,并且在对spring数据和休眠状态的内部进行长时间调试之后,找到了对我有用的解决方案。
因此要在PostgreSQL中使用游标获取数据,应使用带有Stream结果+注释(kotlin语法)的方法:
@QueryHints(QueryHint(name = org.hibernate.annotations.QueryHints.FETCH_SIZE, value = "50"))
该值应为50或其他值-并不是很重要。 可能您输入了错误的提示名称。
答案 2 :(得分:0)
您必须在工作完成后分离实体。
import javax.persistence.EntityManager;
...
@Autowired
private EntityManager entityManager;
...
// Your business logic
productRepository.streamAll().forEach(product -> {
export(product);
// must detach so that garbage collector can reclaim the memory.
entityManager.detach(product);
});