从PostgreSQL流式传输行(具有提取大小)

时间:2019-05-02 12:38:15

标签: java postgresql spring-boot jpa spring-boot-jpa

我想从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)读取数据以及如何以最佳方式从数据库加载行。 我知道我可以进行分页,但是正如在撰写文章中所述,这不是最佳方法。

3 个答案:

答案 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);
});