Spring Webflux + r2dbc 分頁查詢 示例1

1. 概述

本小結(jié)主要區(qū)分分頁的基本概念, 如果已經(jīng)熟悉分頁的原理的同學可以忽略本小結(jié)

2. 分頁原理

本例中, 我們將使用 offset + page 的方式進行分頁, 那么如何計算page和offset之間的關(guān)系呢? 假設(shè)我們有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 |
+--------+--------------+------------+--------+---------+

在我們梳理各種關(guān)系前, 我們先確認一些概念

  • 按page 的方式進行分頁
    比如上面的例子, 我們有11條記錄, 如果我們假設(shè)pagesize為5, page0 為起始頁, 那么page就等于3, 分別是page0, page1, page2
    page: 頁數(shù), 第幾頁
    pagesize: 每一頁記錄的條目數(shù)

  • 按sql查詢條件的方式進行分頁
    還是上面的例子, 假設(shè)offset為5, limit 為5 如果我們執(zhí)行如下查詢

select * from emp_talbe offset 5 limit 5 

我們將得到 6 | Huutte -> 10 | Blank 的五條記錄. 那么可以看出
offset: 游標, 查詢的起始點
limit: 限定查詢記錄個數(shù)
那么此時我們是希望通過使用 offset + limit 的sql 來進行分頁查詢, 那么假設(shè)我們的希望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 
所以自然, 我們可以得出以下我們可能需要用到值的關(guān)系
- 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 接口的實現(xiàn)類 PageRequest

一個比較常用的實現(xiàn)類就是 PageRequest, 那么它實現(xiàn)了很多我們需要的方法, 同時提供of 靜態(tài)方法供我們調(diào)用創(chuàng)建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)
...
}

//調(diào)用
MyRepository.getEmployeebyGender("man", PageRequest.of(8, 10) )

此時, 我們已經(jīng)可以使用現(xiàn)有的實現(xiàn)類滿足我們的需求, 但是我們需要使用使用 offset 進行查詢, 那么接下來我們將要討論如何結(jié)合自己的情況來調(diào)整開發(fā)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容