美文网首页Spring Webflux
Spring Webflux + r2dbc 分页查询 示例1

Spring Webflux + r2dbc 分页查询 示例1

作者: 这个世界是虚拟的 | 来源:发表于2020-06-07 15:19 被阅读0次

    1. 概述

    本小结主要区分分页的基本概念, 如果已经熟悉分页的原理的同学可以忽略本小结

    2. 分页原理

    本例中, 我们将使用 offset + page 的方式进行分页, 那么如何计算page和offset之间的关系呢? 假设我们有11条记录, 比如emp_talbe:

    +--------+--------------+------------+--------+---------+
    | id | name     | hire_date  | salary | dept_id |
    +--------+--------------+------------+--------+---------+
    |      1 |  Hunt       | 2001-05-01 |   5000 |       4   |                    // page 0 , offset = 1
    |      2 | Tony        | 2002-07-15 |   6500 |       1   |
    |      3 | Sarah      | 2005-10-18 |   8000 |       5   |
    |      4 | Rick         | 2007-01-03 |   7200 |       3   |
    |      5 | Martin      | 2008-06-24 |   5600 |    NULL |
    |      6 |  Huntte     | 2001-05-01 |   5000 |       4   |
    |      7 | Montana   | 2002-07-15 |   6500 |       1   |
    |      8 | Connor     | 2005-10-18 |   8000 |       5   |
    |      9 | Deckard   | 2007-01-03 |   7200 |       3   |
    |      10 | Blank     | 2008-06-24 |   5600 |    NULL |
    |      11 | Malank   | 2008-06-24 |   5600 |    NULL |
    +--------+--------------+------------+--------+---------+
    

    在我们梳理各种关系前, 我们先确认一些概念

    • 按page 的方式进行分页
      比如上面的例子, 我们有11条记录, 如果我们假设pagesize为5, page0 为起始页, 那么page就等于3, 分别是page0, page1, page2
      page: 页数, 第几页
      pagesize: 每一页记录的条目数

    • 按sql查询条件的方式进行分页
      还是上面的例子, 假设offset为5, limit 为5 如果我们执行如下查询

    select * from emp_talbe offset 5 limit 5 
    

    我们将得到 6 | Huutte -> 10 | Blank 的五条记录. 那么可以看出
    offset: 游标, 查询的起始点
    limit: 限定查询记录个数
    那么此时我们是希望通过使用 offset + limit 的sql 来进行分页查询, 那么假设我们的希望pagesize 为5, 那么可以简单理解为我们的limit也就是5. 那么如果我们希望查询第0页的记录page0, 那么 offset = 0, limit=5, 查询第1页的记录page1, 那么 offset = 5, limit=5

    // Page 0 :  select * from emp_talbe offset 0 limit 5 
    // Page 1 :  select * from emp_talbe offset 5 limit 5 
    // Page 2 :  select * from emp_talbe offset 10 limit 5 
    所以自然, 我们可以得出以下我们可能需要用到值的关系
    - limit = pagesize
    - pageNumber = offset/limit 取整
    - offset = pageNumber * limit
    - nextPage number = offset + limit
    - hasPrevious = ( offset - limit >= 0 )
    - previousPageNumber = hasPrevious ? offset-limit : 0 
    

    2. Spring R2dbc 对分页的支持

    通过Spring R2dbc的官方文档: https://docs.spring.io/spring-data/r2dbc/docs/1.1.0.RELEASE/reference/html/#r2dbc.core
    我们可以了解到, 我们可以使用 Pageable 对象进行分页查询. 例如:

    Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);
    

    那么接下来我们可以尝试使用这样的方式进行分页查询.

    3. Pageable 接口

    查看源码, 可以看出此接口涵盖了我们基本所需的分页常见方法, 这些方法也在上一步中,我们分析出了我们需要使用的值:

    public interface Pageable {
    
        /**
         * Returns a {@link Pageable} instance representing no pagination setup.
         *
         * @return
         */
        static Pageable unpaged() {
            return Unpaged.INSTANCE;
        }
    
        /**
         * Returns whether the current {@link Pageable} contains pagination information.
         *
         * @return
         */
        default boolean isPaged() {
            return true;
        }
    
        /**
         * Returns whether the current {@link Pageable} does not contain pagination information.
         *
         * @return
         */
        default boolean isUnpaged() {
            return !isPaged();
        }
    
        /**
         * Returns the page to be returned.
         *
         * @return the page to be returned.
         */
        int getPageNumber();
    
        /**
         * Returns the number of items to be returned.
         *
         * @return the number of items of that page
         */
        int getPageSize();
    
        /**
         * Returns the offset to be taken according to the underlying page and page size.
         *
         * @return the offset to be taken
         */
        long getOffset();
    
        /**
         * Returns the sorting parameters.
         *
         * @return
         */
        Sort getSort();
    
        /**
         * Returns the current {@link Sort} or the given one if the current one is unsorted.
         *
         * @param sort must not be {@literal null}.
         * @return
         */
        default Sort getSortOr(Sort sort) {
    
            Assert.notNull(sort, "Fallback Sort must not be null!");
    
            return getSort().isSorted() ? getSort() : sort;
        }
    
        /**
         * Returns the {@link Pageable} requesting the next {@link Page}.
         *
         * @return
         */
        Pageable next();
    
        /**
         * Returns the previous {@link Pageable} or the first {@link Pageable} if the current one already is the first one.
         *
         * @return
         */
        Pageable previousOrFirst();
    
        /**
         * Returns the {@link Pageable} requesting the first page.
         *
         * @return
         */
        Pageable first();
    
        /**
         * Returns whether there's a previous {@link Pageable} we can access from the current one. Will return
         * {@literal false} in case the current {@link Pageable} already refers to the first page.
         *
         * @return
         */
        boolean hasPrevious();
    
        /**
         * Returns an {@link Optional} so that it can easily be mapped on.
         *
         * @return
         */
        default Optional<Pageable> toOptional() {
            return isUnpaged() ? Optional.empty() : Optional.of(this);
        }
    }
    

    3. Pageable 接口的实现类 PageRequest

    一个比较常用的实现类就是 PageRequest, 那么它实现了很多我们需要的方法, 同时提供of 静态方法供我们调用创建PageRequest, 例如

    /**
         * Creates a new unsorted {@link PageRequest}.
         *
         * @param page zero-based page index, must not be negative.
         * @param size the size of the page to be returned, must be greater than 0.
         * @since 2.0
         */
        public static PageRequest of(int page, int size) {
            return of(page, size, Sort.unsorted());
        }
    
        /**
         * Creates a new {@link PageRequest} with sort parameters applied.
         *
         * @param page zero-based page index.
         * @param size the size of the page to be returned.
         * @param sort must not be {@literal null}, use {@link Sort#unsorted()} instead.
         * @since 2.0
         */
        public static PageRequest of(int page, int size, Sort sort) {
            return new PageRequest(page, size, sort);
        }
    /**
         * Creates a new {@link PageRequest} with sort direction and properties applied.
         *
         * @param page zero-based page index, must not be negative.
         * @param size the size of the page to be returned, must be greater than 0.
         * @param direction must not be {@literal null}.
         * @param properties must not be {@literal null}.
         * @since 2.0
         */
        public static PageRequest of(int page, int size, Direction direction, String... properties) {
            return of(page, size, Sort.by(direction, properties));
        }
    
    

    那么我们比如要查询第8页, 限定每页10个记录, 我们只需使用

    PageRequest.of(8, 10);
    

    使用在Repository 的方法中:

    MyRepository extends ReactiveCrudRepository<Employee, UUID>{
    ...
     Flux<Employee> getEmployeebyGender((@Param("gender") String gender, Pageable pageable)
    ...
    }
    
    //调用
    MyRepository.getEmployeebyGender("man", PageRequest.of(8, 10) )
    

    此时, 我们已经可以使用现有的实现类满足我们的需求, 但是我们需要使用使用 offset 进行查询, 那么接下来我们将要讨论如何结合自己的情况来调整开发

    相关文章

      网友评论

        本文标题:Spring Webflux + r2dbc 分页查询 示例1

        本文链接:https://www.haomeiwen.com/subject/jduazhtx.html