我有一个大表,我想通过Spring Data Repository访问。
目前,我正在尝试扩展PagingAndSortingRepository
接口,但似乎我只能定义返回列表的方法,例如:
public interface MyRepository extends
PagingAndSortingRepository<MyEntity, Integer>
{
@Query(value="SELECT * ...")
List<MyEntity> myQuery(Pageable p);
}
另一方面,findAll()
附带的PagingAndSortingRepository
方法返回Iterable
(我认为数据未加载到内存中)。
是否可以定义同时返回Iterable和/或不会立即将所有数据加载到内存中的自定义查询?
是否有处理大型表的替代方案?
答案 0 :(得分:9)
我们在这里有经典的咨询答案:这取决于。由于该方法的实现是特定于商店的,因此我们依赖于底层商店API。在JPA的情况下,由于….getResultList()
返回List
,因此无法提供流式访问。因此,我们还将List
公开给客户端,因为特别是JPA开发人员可能习惯使用列表。因此,对于JPA,唯一的选择是使用分页API。
对于像Neo4j这样的商店,我们支持流式访问,因为存储库会在CRUD方法上返回Iterable
以及执行finder方法。
答案 1 :(得分:3)
findAll()
的{{3}}只是将所有实体的整个列表加载到内存中。它的Iterable
返回类型并不意味着它实现了某种数据库级别的游标处理。
另一方面,您的自定义myQuery(Pageable)
方法只会加载一页实体,因为生成的实现会遵循其Pageable
参数。您可以将其返回类型声明为Page
或List
。在后一种情况下,您仍然会收到相同(受限制)数量的实体,但不会收到Page
另外携带的元数据。
所以你基本上做了正确的事情,以避免在自定义查询中将所有实体加载到内存中。
请查看implementation。
答案 2 :(得分:0)
我认为您正在寻找的是 Spring Data JPA Stream 。它极大地提高了数据获取的性能,尤其是在具有数百万条记录的数据库中。就您而言,您可以考虑几种选择
为了使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实体将是只读的。如果您的要求不同,请确保根据您的要求相应地更改这些设置。