最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java GraphQL數(shù)據(jù)加載器批處理的實(shí)現(xiàn)詳解

 更新時(shí)間:2023年12月22日 15:26:42   作者:happyEnding  
GraphQL 數(shù)據(jù)加載器是優(yōu)化 GraphQL API 的關(guān)鍵組件,旨在解決臭名昭著的 N+1 查詢問(wèn)題,在本中,我們將深入研究其批處理功能,感興趣的小伙伴可以了解下

介紹

GraphQL 是一種強(qiáng)大而靈活的 API 查詢語(yǔ)言,使客戶端能夠準(zhǔn)確請(qǐng)求他們所需的數(shù)據(jù),從而消除信息的過(guò)度獲取和獲取不足。然而,隨著 GraphQL 查詢變得更加復(fù)雜并涉及多個(gè)數(shù)據(jù)源,有效地檢索數(shù)據(jù)并向客戶端提供數(shù)據(jù)可能具有挑戰(zhàn)性。這就是 GraphQL 數(shù)據(jù)加載器發(fā)揮作用的地方。

GraphQL 數(shù)據(jù)加載器是優(yōu)化 GraphQL API 的關(guān)鍵組件,旨在解決臭名昭著的 N+1 查詢問(wèn)題,該問(wèn)題在 GraphQL 服務(wù)器重復(fù)獲取相關(guān)項(xiàng)目列表的相同數(shù)據(jù)時(shí)發(fā)生。數(shù)據(jù)加載器通過(guò)批處理和緩存請(qǐng)求,幫助簡(jiǎn)化從各種來(lái)源(例如數(shù)據(jù)庫(kù)、API,甚至本地緩存)獲取數(shù)據(jù)的過(guò)程。通過(guò)這樣做,他們顯著提高了 GraphQL 查詢的效率和性能。

在本中,我們將深入研究批處理功能,通過(guò)查看數(shù)據(jù)加載器的 java 實(shí)現(xiàn)來(lái)探索它如何發(fā)揮其魔力。

批處理

批處理是將多個(gè)單獨(dú)的數(shù)據(jù)檢索請(qǐng)求收集到單個(gè)批處理請(qǐng)求中的過(guò)程,從而減少對(duì)數(shù)據(jù)源的調(diào)用次數(shù)。在處理 GraphQL 查詢中的關(guān)系時(shí),這一點(diǎn)尤其重要。

考慮一個(gè)典型場(chǎng)景,其中 GraphQL 查詢請(qǐng)求一個(gè)項(xiàng)目列表,以及每個(gè)項(xiàng)目的附加相關(guān)數(shù)據(jù)(例如用戶信息)。如果不進(jìn)行批處理,這將導(dǎo)致對(duì)每個(gè)項(xiàng)目進(jìn)行單獨(dú)的數(shù)據(jù)庫(kù)查詢或 API 請(qǐng)求,從而導(dǎo)致 N+1 查詢問(wèn)題。通過(guò)批處理,可以將這些單獨(dú)的請(qǐng)求有效地組合成單個(gè)請(qǐng)求,從而大大減少數(shù)據(jù)源的往返次數(shù)

Java 數(shù)據(jù)加載器批處理

假設(shè)我們有一個(gè)如下所示的 graphql 查詢

{
  user {
    name
    friends {
      name
    }
  }
}

它生成以下查詢結(jié)果

{
  "user": {
    "name": "zhangsan",
    “friends”: [
      {
        "name": "lisi",
      },
      {
        "name": "wanmgwu",
      },
      {
        "name": "zhouliu",
      }
    ]
  }
}

一個(gè)簡(jiǎn)單的實(shí)現(xiàn)方法是為查詢響應(yīng)中的每個(gè)用戶執(zhí)行一次調(diào)用以檢索一個(gè)用戶對(duì)象,即 4 次調(diào)用,一次針對(duì)根對(duì)象,一次針對(duì)列表中的每個(gè)好友。

然而,它DataLoader不會(huì)立即執(zhí)行遠(yuǎn)程調(diào)用,它只是將調(diào)用排入隊(duì)列并返回一個(gè) Promise ( CompletableFuture) 來(lái)傳遞用戶對(duì)象。一旦我們將構(gòu)建查詢結(jié)果的所有調(diào)用排入隊(duì)列,我們??必須請(qǐng)求DataLoader開始執(zhí)行它們。這就是奇跡發(fā)生的地方。將DataLoader開始提取每次調(diào)用的用戶 ID 并將其放入一個(gè)列表中,該列表將用于查詢我們配置的后端,并僅使用一個(gè)請(qǐng)求即可檢索用戶列表。

批處理通常按級(jí)別進(jìn)行,在本例中我們有 2 個(gè)級(jí)別。root 用戶和他的朋友。通過(guò)使用DataLoaderbatchig,此響應(yīng)將只需要 2 次調(diào)用。

代碼示例

讓我們添加一些代碼來(lái)展示如何使用它。

我們首先需要擁有一個(gè)BatchLoader. 它將從用戶后端批量加載用戶,從而減少對(duì)該后端的 API 調(diào)用量。

List<User> loadUsersById(List<Long> userIds) {
   System.out.println("Api call to load users = " + userIds);
   return users.stream().filter(u -> userIds.contains(u.id())).toList();
}

BatchLoader<Long, User> userBatchLoader = new BatchLoader<>() {
   @Override
   public CompletionStage<List<User>> load(List<Long> userIds) {
      return CompletableFuture.supplyAsync(() -> {
         return loadUsersById(userIds);
      });
   }
};

然后我們需要?jiǎng)?chuàng)建一個(gè)DataLoader將使用前面的BatchLoader來(lái)執(zhí)行整個(gè)用戶樹的加載。

var userLoader = DataLoaderFactory.newDataLoader(userBatchLoader);

var userDTO = new UserDTO();
userLoader.load(1L).thenAccept(user -> {
   userDTO.id = user.id();
   userDTO.name = user.name();
   user.friends().forEach(friendId -> {
      userLoader.load(friendId).thenAccept(friend -> {
         userDTO.friends.add(new FriendDTO(friend.id(), friend.name()));
      });
   });
});

userLoader.dispatchAndJoin();
System.out.println(userDTO);

它將產(chǎn)生以下調(diào)試輸出

Api call to load users = [1]
Api call to load users = [2, 3, 4]
UserDTO{id=1, name='John', friends=[FriendDTO[id=2, name=Jane], FriendDTO[id=3, name=Bob], FriendDTO[id=4, name=Alice]]}

如果您對(duì)它的內(nèi)部工作原理感到好奇,我將向您展示用戶的一種自定義實(shí)現(xiàn)DataLoader。不是真正的。只需一個(gè)簡(jiǎn)化版本即可幫助您了解全貌。

static class UserLoader {
   BatchLoader<Long, User> userBatchLoader;

   record QueueEntry(long id, CompletableFuture<User> value) { }
   List<QueueEntry> loaderQueue = new ArrayList<>();

   UserLoader(BatchLoader<Long, User> userBatchLoader) {
      this.userBatchLoader = userBatchLoader;
   }

   CompletableFuture<User> load(long userId) {
      var future = new CompletableFuture<User>();
      loaderQueue.add(new QueueEntry(userId, future));
      return future;
   }

   List<User> dispatchAndJoin() {
      List<User> joinedResults = dispatch().join();
      List<User> results = new ArrayList<>(joinedResults);
      while (loaderQueue.size() > 0) {
         joinedResults = dispatch().join();
         results.addAll(joinedResults);
      }
      return results;
   }

   CompletableFuture<List<User>> dispatch() {
      var userIds = new ArrayList<Long>();
      final List<CompletableFuture<User>> queuedFutures = new ArrayList<>();

      loaderQueue.forEach(qe -> {
         userIds.add(qe.id());
         queuedFutures.add(qe.value());
      });

      loaderQueue.clear();

      var userFutures = userBatchLoader.load(userIds).toCompletableFuture();

      return userFutures.thenApply(users -> {
         for (int i = 0; i < queuedFutures.size(); i++) {
            var userId = userIds.get(i);
            var user = users.get(i);
            var future = queuedFutures.get(i);
            future.complete(user);
         }
         return users;
      });
   }
}

所以,首先看一下CompletableFuture<User> load(long userId),它不執(zhí)行任何 userId 查找,它只是:

  • 將查找排入隊(duì)列
  • 生成一個(gè),CompletableFuture讓您根據(jù)您提供的查找鏈接進(jìn)一步查找。因此,查找被推遲,直到我們實(shí)際使用dispatchAndJoin()

現(xiàn)在,看看List<User> dispatchAndJoin()。一旦我們準(zhǔn)備好檢索用戶列表,就會(huì)調(diào)用該函數(shù)。它會(huì):

1.調(diào)用 CompletableFuture<List<User>> dispatch()將執(zhí)行以下操作:

將所有 userId 分組到一個(gè)列表中,并將其發(fā)送到底層BatchLoader ,底層對(duì)后端執(zhí)行實(shí)際的 API 調(diào)用。

完成我們注冊(cè)查找時(shí)(當(dāng)我們調(diào)用 )時(shí)提供的 CompletableFuture CompletableFuture<User> load(long userId),從而向 中添加更多元素loaderQueue。此時(shí),下一級(jí)的 userId 查找已排隊(duì)。

2.當(dāng)中還有剩余元素時(shí)重復(fù)該過(guò)程loaderQueue

到此這篇關(guān)于Java GraphQL數(shù)據(jù)加載器批處理的實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Java GraphQL數(shù)據(jù)加載器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你怎么使用Java實(shí)現(xiàn)WebSocket

    教你怎么使用Java實(shí)現(xiàn)WebSocket

    這篇文章主要介紹了教你怎么使用Java WebSocket,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05
  • java中Iterator和ListIterator實(shí)例詳解

    java中Iterator和ListIterator實(shí)例詳解

    這篇文章主要介紹了java中Iterator和ListIterator實(shí)例詳解,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • JAVA MyBatis入門學(xué)習(xí)過(guò)程記錄

    JAVA MyBatis入門學(xué)習(xí)過(guò)程記錄

    MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架。這篇文章主要介紹了mybatis框架入門學(xué)習(xí)教程,需要的朋友可以參考下,希望能幫助到你
    2021-06-06
  • Mybatis-Plus使用ID_WORKER生成主鍵id重復(fù)的解決方法

    Mybatis-Plus使用ID_WORKER生成主鍵id重復(fù)的解決方法

    本文主要介紹了Mybatis-Plus使用ID_WORKER生成主鍵id重復(fù)的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • IntelliJ?IDEA?2023.2最新版激活方法及驗(yàn)證ja-netfilter配置是否成功

    IntelliJ?IDEA?2023.2最新版激活方法及驗(yàn)證ja-netfilter配置是否成功

    隨著2023.2版本的發(fā)布,用戶們渴望了解如何激活這個(gè)最新版的IDE,本文將介紹三種可行的激活方案,包括許可證服務(wù)器、許可證代碼和idea?vmoptions配置,幫助讀者成功激活并充分利用IDEA的功能,感興趣的朋友參考下吧
    2023-08-08
  • Sentinel結(jié)合Nacos實(shí)現(xiàn)數(shù)據(jù)持久化過(guò)程詳解

    Sentinel結(jié)合Nacos實(shí)現(xiàn)數(shù)據(jù)持久化過(guò)程詳解

    這篇文章主要介紹了Sentinel結(jié)合Nacos實(shí)現(xiàn)數(shù)據(jù)持久化過(guò)程,要持久化的原因是因?yàn)槊看螁?dòng)Sentinel都會(huì)使之前配置的規(guī)則就清空了,這樣每次都要再去設(shè)定規(guī)則顯得非常的麻煩,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • MyBatisPlus 一對(duì)多、多對(duì)一、多對(duì)多的完美解決方案

    MyBatisPlus 一對(duì)多、多對(duì)一、多對(duì)多的完美解決方案

    這篇文章主要介紹了MyBatisPlus 一對(duì)多、多對(duì)一、多對(duì)多的完美解決方案,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • MybatisPlus只取一條記錄的兩種方法實(shí)現(xiàn)

    MybatisPlus只取一條記錄的兩種方法實(shí)現(xiàn)

    本文介紹了MyBatis-Plus2.x和3.x版本在IService接口獲取單條記錄的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-07-07
  • java的Console類的使用方法及實(shí)例

    java的Console類的使用方法及實(shí)例

    這篇文章主要介紹了java的Console類的使用方法及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • IDEA中沒(méi)有Mapper.xml模板選項(xiàng)的處理方法

    IDEA中沒(méi)有Mapper.xml模板選項(xiàng)的處理方法

    這篇文章主要介紹了IDEA中沒(méi)有Mapper.xml模板選項(xiàng)的處理方法,需其實(shí)解決方法很簡(jiǎn)單,只需要在idea中導(dǎo)入模板即可,本文圖文的形式給大家分享解決方法,需要的朋友可以參考下
    2021-04-04

最新評(píng)論

韩城市| 温泉县| 新宾| 威信县| 二连浩特市| 宝兴县| 永靖县| 克东县| 沾化县| 桑日县| 广元市| 利津县| 兰西县| 定襄县| 嵩明县| 新邵县| 巴彦县| 天水市| 崇礼县| 武强县| 马关县| 宜昌市| 唐山市| 古蔺县| 遂昌县| 德令哈市| 东城区| 陇川县| 洞口县| 石景山区| 崇州市| 维西| 宜城市| 龙陵县| 泗阳县| 道孚县| 鄂尔多斯市| 乐山市| 玛纳斯县| 通州市| 咸宁市|