如何使用Spring Data Repositories处理大量数据?

时间:2013-03-05 18:55:28

标签: spring repository spring-data

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

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

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

另一方面,findAll()附带的PagingAndSortingRepository方法返回Iterable(我认为数据未加载到内存中)。

是否可以定义同时返回Iterable和/或不会立即将所有数据加载到内存中的自定义查询?

是否有处理大型表的替代方案?

3 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:3)

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

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

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

请查看implementation

答案 2 :(得分:0)

我认为您正在寻找的是 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实体将是只读的。如果您的要求不同,请确保根据您的要求相应地更改这些设置。