滾動

滾動是一種更精細的方法,用於迭代更大的結果集塊。滾動包含穩定的排序、滾動型別(基於偏移或基於鍵集)和結果限制。您可以透過屬性名稱定義簡單的排序表示式,並透過查詢派生使用 TopFirst 關鍵字 定義靜態結果限制。您可以連線表示式以將多個條件收集到一個表示式中。

滾動查詢返回一個 Window<T>,它允許獲取元素的滾動位置,以獲取下一個 Window<T>,直到您的應用程式消耗了整個查詢結果。與透過獲取下一批結果來消耗 Java Iterator<List<…>> 類似,查詢結果滾動允許您透過 Window.positionAt(…) 訪問 ScrollPosition,如下例所示

Window<User> users = repository.findFirst10ByLastnameOrderByFirstname("Doe", ScrollPosition.offset());
do {

  for (User u : users) {
    // consume the user
  }

  if (users.isLast() || users.isEmpty()) {
    break;
  }

  // obtain the next Scroll
  users = repository.findFirst10ByLastnameOrderByFirstname("Doe", users.positionAt(users.size() - 1));
} while (!users.isEmpty());

ScrollPosition 標識元素在整個查詢結果中的確切位置。查詢執行將位置引數視為排他性,結果將從給定位置之後開始。ScrollPosition#offset()ScrollPosition#keyset()ScrollPosition 的特殊形式,表示滾動操作的開始。

上面的示例展示了靜態排序和限制。您可以定義接受 Sort 物件以定義更復雜的排序順序或按請求排序的查詢方法。類似地,提供 Limit 物件允許您按請求定義動態限制,而不是應用靜態限制。有關動態排序和限制的更多資訊,請參閱 查詢方法詳細資訊

透過消耗 Window 例項進行滾動需要相當多的條件才能實現最佳的資料庫往返,並且可能很快成為一個重複的任務,可以使用 WindowIterator 進行簡化。

WindowIterator 提供了一個實用程式,透過消除檢查下一個 Window 是否存在以及應用 ScrollPosition 的需要來簡化跨 Window 的滾動。

WindowIterator<User> users = WindowIterator.of(position -> repository.findFirst10ByLastnameOrderByFirstname("Doe", position))
  .startingAt(ScrollPosition.offset());

while (users.hasNext()) {
  User u = users.next();
  // consume the user
}

使用偏移進行滾動

偏移滾動類似於分頁,使用偏移計數器跳過一定數量的結果,讓資料來源只返回從給定偏移開始的結果。這種簡單機制避免了將大量結果傳送到客戶端應用程式。但是,大多數資料庫在您的伺服器返回結果之前需要具體化完整的查詢結果。

示例 1. 將 OffsetScrollPosition 與 Repository 查詢方法一起使用
interface UserRepository extends Repository<User, Long> {

  Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, OffsetScrollPosition position);
}

WindowIterator<User> users = WindowIterator.of(position -> repository.findFirst10ByLastnameOrderByFirstname("Doe", position))
  .startingAt(OffsetScrollPosition.initial()); (1)
1 從沒有偏移開始,以包含位置 0 處的元素。

ScrollPosition.offset()ScrollPosition.offset(0L) 之間存在差異。前者表示滾動操作的開始,不指向任何特定偏移,而後者標識結果的第一個元素(位於位置 0)。鑑於滾動的排他性,使用 ScrollPosition.offset(0) 會跳過第一個元素並轉換為偏移量 1

使用鍵集過濾進行滾動

基於偏移的查詢要求大多數資料庫在您的伺服器返回結果之前具體化整個結果。因此,儘管客戶端只看到請求結果的一部分,但您的伺服器需要構建完整結果,這會造成額外的負載。

鍵集過濾方法透過利用資料庫的內建功能來檢索結果子集,旨在減少單個查詢的計算和 I/O 要求。此方法透過將鍵傳遞給查詢來維護一組鍵以恢復滾動,從而有效地修改您的過濾條件。

鍵集過濾的核心思想是使用穩定的排序順序開始檢索結果。一旦您想要滾動到下一個塊,您將獲得一個 ScrollPosition,用於重建排序結果中的位置。ScrollPosition 捕獲當前 Window 中最後一個實體的鍵集。為了執行查詢,重建會重寫條件子句以包含所有排序欄位和主鍵,以便資料庫可以利用潛在的索引來執行查詢。資料庫只需要從給定鍵集位置構建一個更小的結果,而無需完全具體化大量結果,然後跳過結果直到達到特定偏移量。

鍵集過濾要求鍵集屬性(用於排序的屬性)不可為空。此限制適用於儲存特定的比較運算子的 null 值處理以及對索引源執行查詢的需要。對可空屬性進行鍵集過濾將導致意外結果。

KeysetScrollPosition 與 Repository 查詢方法一起使用
interface UserRepository extends Repository<User, Long> {

  Window<User> findFirst10ByLastnameOrderByFirstname(String lastname, KeysetScrollPosition position);
}

WindowIterator<User> users = WindowIterator.of(position -> repository.findFirst10ByLastnameOrderByFirstname("Doe", position))
  .startingAt(ScrollPosition.keyset()); (1)
1 從最開始處開始,不應用額外的過濾。

當您的資料庫包含與排序欄位匹配的索引時,鍵集過濾效果最佳,因此靜態排序效果很好。應用鍵集過濾的滾動查詢要求查詢返回用於排序順序的屬性,並且這些屬性必須在返回的實體中進行對映。

您可以使用介面和 DTO 投影,但請確保包含所有您已排序的屬性,以避免鍵集提取失敗。

在指定 Sort 順序時,包含與您的查詢相關的排序屬性就足夠了;如果您不想,則無需確保唯一的查詢結果。鍵集查詢機制透過包含主鍵(或複合主鍵的任何剩餘部分)來修改您的排序順序,以確保每個查詢結果都是唯一的。

© . This site is unofficial and not affiliated with VMware.