19

我有一个大表,我想通过 Spring Data Repository 访问它。

目前,我正在尝试扩展PagingAndSortingRepository接口,但似乎我只能定义返回列表的方法,例如:

public interface MyRepository extends 
        PagingAndSortingRepository<MyEntity, Integer>
{
  @Query(value="SELECT * ...")
  List<MyEntity> myQuery(Pageable p);
}

另一方面,findAll()附带的方法PagingAndSortingRepository返回一个Iterable(我假设数据没有加载到内存中)。

是否可以定义自定义查询也返回 Iterable 和/或不一次将所有数据加载到内存中?

有没有其他方法可以处理大表?

4

3 回答 3

11

我们在这里有经典的咨询答案:视情况而定。由于该方法的实现是特定于存储的,因此我们依赖于底层存储 API。在 JPA 的情况下,没有机会提供流式访问作为….getResultList()返回一个List. 因此,我们还List向客户端公开,因为特别是 JPA 开发人员可能习惯于使用列表。因此,对于 JPA,唯一的选择是使用分页 API。

对于像 Neo4j 这样的商店,我们支持流式访问,因为存储库返回IterableCRUD 方法以及 finder 方法的执行。

于 2013-03-06T09:55:03.717 回答
8

实现只是将所有实体的findAll()整个列表加载到内存中。它的Iterable返回类型并不意味着它实现了某种数据库级别的游标处理。

另一方面,您的自定义myQuery(Pageable)方法将仅加载一个页面的实体,因为生成的实现尊重其Pageable参数。您可以将其返回类型声明为PageList。在后一种情况下,您仍然会收到相同(受限)数量的实体,但不会收到 aPage额外携带的元数据。

因此,您基本上做了正确的事情来避免在自定义查询中将所有实体加载到内存中。

请在此处查看相关文档

于 2013-03-05T23:44:20.343 回答
2

我认为您正在寻找的是Spring Data JPA Stream。它为数据获取带来了显着的性能提升,尤其是在具有数百万条记录的数据库中。在您的情况下,您有几个可以考虑的选项

  1. 一次在内存中拉取所有数据
  2. 每次使用分页和阅读页面
  3. 使用 Apache Spark 之类的东西
  4. 使用 Spring Data JPA 流式传输数据

为了使 Spring Data JPA Stream 工作,我们需要修改我们MyRepository的返回Stream<MyEntity>,如下所示:

public interface MyRepository extends PagingAndSortingRepository<MyEntity, Integer> {
    @QueryHints(value = {
        @QueryHint(name = HINT_CACHEABLE, value = "false"),
        @QueryHint(name = READ_ONLY, value = "true")
    })
    @Query(value="SELECT * ...")
    Stream<MyEntity> myQuery();
}

在这个例子中,我们禁用了二级缓存并提示 Hibernate 实体将是只读的。如果您的要求不同,请确保根据您的要求相应地更改这些设置。

于 2019-11-19T18:56:57.267 回答