Spring JPA:使用分页查找多个 ID

Posted

技术标签:

【中文标题】Spring JPA:使用分页查找多个 ID【英文标题】:Spring JPA: find by multiple IDs with Pagination 【发布时间】:2021-06-22 02:22:27 【问题描述】:

如何将分页应用于以下查询:

@Repository
public interface PostRepository extends JpaRepository<Post, Long> 

  @Query("select b from Building b where b.id in :ids" )
  Page<Post> findByIds(@Param("ids") List<Long> postIdsList);
...

所有现有示例均基于接受Pageable 对象的标准findAll 方法:public Page findAll(Pageable pageable);

问题是:

控制器方法签名应该是什么 存储库方法参数应该是什么 应如何以及将哪些参数传递给控制器​​方法 我应该总是为每个请求拆分帖子 ID Spring 是否会进行一次查询并将所有找到的帖子保存在内存中,或者每次下一页/上一页都会点击查询?如果是这样,它如何找出用于查找下一个/上一个帖子的 ID?

最初的实现如下:

@RestController
class PostsController 

    @Autowired

    private PostService postService;

    @GetMapping("/posts", params = "ids")
    public List<Post> getPaginatedPosts(@RequestParam List<Long> ids) 

        return postService.findPaginatedPosts(ids);
    


@Repository
@Repository
public interface PostRepository extends JpaRepository<Post, Long> 

  @Query("select b from Building b where b.id in :ids" )
  Page<Post> findByIds(@Param("ids") List<Long> postIdsList);
...

我省略了 PostServiceImpl 中的代码 qui 实现了 PostService 并且只调用了 PostRepository#findByIds 方法。

【问题讨论】:

baeldung.com/rest-api-pagination-in-spring 这引出了一个问题:如果客户端知道它应该获取的 id,为什么不通过简单地限制请求中发送的 id 列表来处理分页? @crizzis:因为前面有超过 20 个 ID,通过添加分页/排序参数来调整 URL 比玩集合并到处剪切它更容易页。所以我更愿意让 Spring 就地执行。更重要的是,我认为这就是大多数分页库的工作方式。 【参考方案1】:

试试这个:

@Repository
public interface PostRepository extends JpaRepository<Post, Long> 

  @Query( "select o from Building b where id in :ids" )
  Page<Post> findByIds(@Param("ids") List<Long> postIdsList,Pageable pageRequest);
...

在控制器中询问 pageSize 和 pageNo,如果它为空,则设置一个默认值,例如 pageNo = 0, pageSize=10。

将这些值传递给服务层服务应该创建可分页对象调用findByIds(ids, pagable); 并将页面返回给控制器。

你可以参考这个: https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-seven-pagination/

【讨论】:

感谢您的链接,即使它是 2012 年的,它仍然有用:)。我还看了最新的Spring Data Rest docs。【参考方案2】:

这是我给你的解决方案,加上上面的 cmets 建议。

    定义一个可以扩展 JpaRepositoryPagingAndSortingRepository 的存储库,如下所示:
@Repository
public interface PostRepository extends JpaRepository<Post, Long> 

  @Query("select p from Post p where p.id in :ids" )
  Page<Post> findByIds(@Param("ids") List<Long> postIdsList);
...

    创建服务类及其实现:
public interface PostService 
  List<PostDTO> getPostsList(List<Long> ids, Pageable pageable);
...


@Service
@Slf4j
public class PostServiceImpl implements PostService 
...
  @Autowired
  private PostRepository postRepository;

...
  @Override
  public List<PostDTO> getPostsList(List<Long> ids, Pageable pageable) 
        List<PostDTO> resultList = new ArrayList<>();
        Page<Post> paginatedPosts = postRepository.findByIds(ids, pageable);

        List<Post> posts = paginatedPosts.getContent();
        posts.forEach(post -> resultList.add(convertToPostDTO(post)));

        return resultList;
    

最后,PostsController 部分:

@RestController
@RequestMapping("/api")
class PostsController 

  @Autowired
  private PostService postService;
...
    @GetMapping(value = "/posts", params = "ids")
    public ResponseEntity <List<PostDTO>>getPostsList(@RequestParam List<Long> ids, Pageable pageable) 
        List<PostDTO> postsList = postService.getPostsList(ids, pageable);
        return new ResponseEntity<>(postsList, HttpStatus.OK);
    

请求应该包含pagesize URL参数(默认情况下,page0size20):

http://localhost:8080/api/posts?ids=1050,1049,1048,1043,1042,1041,1040,1039,1038&size=5&page=1&sort=id

在上面的示例中,我总共有 9 条记录,我明确设置了参数以将结果列表限制为 5 条并仅显示第二页以及按 id 对它们进行排序。

如果您不提供它们,将使用默认值(page = 0,size = 20)。

【讨论】:

以上是关于Spring JPA:使用分页查找多个 ID的主要内容,如果未能解决你的问题,请参考以下文章

spring cloud 搭建(多JPA,JPA分页)

JPA - 对孩子列表进行分页

java web spring jpa 在以接口为dao的方法里使用原生sql,联合查找没有对应实体,用啥来接收? 求大神

Spring Data JPA之删除和修改

Spring Boot2.0 JPA 实现分页(简单查询分页、复杂查询分页)

使用连接表存储库的@manytomany 中的 Spring 数据 jpa 规范和可分页