天天看點

API做翻頁的兩種思路

在開發API的時候,有時候資料太多了,就需要分頁讀取。

這種方式就是會提供一個每頁筆數(page size)來定義傳回條目的最大數,提供一個頁數(page number)來表示從哪裡開始讀取資料。

例如:

這句話的意思就是從該表中讀取資料,按照Name字段降序排序,從第10筆資料後開始讀取,一共讀取5筆(可能不足5筆)。

這就相當于page size = 5,page number = 3的分頁讀取。

Offset-based分頁方式實作起來非常的簡單,對使用者來說體驗也比較好。但是還有有一些劣勢的:

對于大規模的資料集,效率不夠高。因為資料庫需要進行count和skip操作。

如果資料經常發生變化,那麼結果不可信。在查詢的時候如果插入或删除了資料,那麼某條資料可能會出現兩次或者翻頁的時候越界了。

在分布式系統中實作起來略麻煩。這種情況下,你可能需要掃描不同的資料碎片,然後才能得到想要的資料。

總體來說,當允許結果出現誤差的時候,Offset-based分頁還是很好用的。

為了解決Offset-based分頁的那些問題,可以采用Cursor-based分頁。

這種方式是這樣的:用戶端首先發送請求,請求裡提供所需資料的數量。然後伺服器響應請求,傳回這些數量的資料(如果有這麼多資料的話),同時還會傳回一個遊标(Cursor)。在下一次請求中,用戶端除了發送請求資料的數量之外,還把這個cursor也傳送過去,這個cursor就表示這次所要讀取的資料的開始位置。

這看起來和Offset-based分頁差别不大,但是卻更有效率。資料庫裡面的資料可以根據cursor值來擷取。

這個例子裡,上次請求傳回的cursor(Id字段)值為15,這次要擷取Id比15大的連續的5條資料。

這裡的Id字段本身就是一個索引,是以查詢起來非常快。

在這次請求的響應裡,可以把本次結果的最後一條的Id作為cursor再傳回去:

API做翻頁的兩種思路

是以傳回的cursor值為23,以供下次讀取。

Cursor-based翻頁的優點是:

性能好。因為cursor字段通常都是索引列,查起來很快。

一緻性。添加和删除資料并不影響傳回的結果,翻頁時同一筆資料也隻會被傳回一次。

Cursor-based翻頁通常适用于大量和動态的資料集,但是它也有一些缺點:

無法跳轉到指定的頁。Cursor-based翻頁隻能一頁一頁周遊結果。

結果必須基于一個唯一并且順序的字段。不可以讓添加記錄到任意位置。

實作起來比Offset-based複雜一點,尤其對用戶端來說。

對于Cursor字段的選擇:

Id,順序的主鍵。

時間戳。

加密字元串。它們看起來像随機字元串,但實際上通常是Cursor裡加入了額外的資訊。

總體來說Cursor-based翻頁還是更适合于高吞吐的應用,這種情況下用戶端通常需要掃描整個資料集。

設定每頁的最大筆數限制。

針對大資料集,盡量不要使用Offset-based分頁。

分頁的預設排序,通常會把新的資料先傳回,舊的資料往後翻。

沒分頁的API盡量去實作分頁。

分頁的時候,最好把下一頁的連結一同傳回,并鼓勵用戶端使用這個連結,參考HATEOAS。這樣以後你改變翻頁政策的時候,用戶端不會爆掉。

不要在Cursor裡加入敏感資訊。

API做翻頁的兩種思路