java - DataLoader批量加载bug(MyBatis、JavaEE)

标签 java graphql jax-rs mybatis java-ee-7

我的生产中有graphql,禁止分享代码。我正在使用 graphql-java-servlet,作为 ORM,我使用 MyBatis。

<dependency>
     <groupId>com.graphql-java-kickstart</groupId>
     <artifactId>graphql-java-servlet</artifactId>
     <version>9.2.0</version>
</dependency>

启用 BatchLoading 后,我发现 graphQL DataLoader 混淆了批量请求实体的位置。如果查看 futureCacheMap 也很容易检查,您会发现 Key(Id) 和 Value(Entity) 具有不同的 id。

经过调试,我没有找到graphQL如何在batchLoading(1000 psc)之后解析Entities的方式。所以我决定我应该进行一些排序,所以我实现了它,但它并没有解决问题。

例如: 我有 Parent.class,里面有 Childs。

class Parent {
    private Long id;
    private List<Long> childsIds;
}

我有 ChildDataloader

private BatchLoader<Long, Child> buildBatchLoader() {
    return list -> > CompletableFuture.supplyAsync(() -> childService.findByIds(list));                
    }

private DataLoader<Long, Child> buildDataLoader(BatchLoader batchLoader) {
    DataLoaderOptions options = DataLoaderOptions.newOptions();
    options.setMaxBatchSize(1000);
    return new DataLoader<Long, Child>(batchLoader, options);
    }
}

我有 ChildsFetcher,我调用 dataLoader.loadMany()

public class ChildsFetcher implements DataFetcher<CompletableFuture<List<Child>>>{

    private static final String PK_FIELD_NAME = "childsIds";

    @Override
    public CompletableFuture<List<LoadDefinitionDTO>> get(DataFetchingEnvironment environment) {
        GraphQLContext context = environment.getContext();
        DataLoaderRegistry dataLoaderRegistry = context.getDataLoaderRegistry().orElseThrow(
                () -> new DalException("there was no dataLoaderRegistry in context", Response.Status.INTERNAL_SERVER_ERROR)
        );
        List<Long> childsIds = getParentFieldValue(environment, PK_FIELD_NAME , List.class);

        DataLoader<Long, Child> childDataLoader = dataLoaderRegistry.getDataLoader("childDataLoader");
        return childDataLoader.loadMany(childsIds)
    }
}

例如,我有 2 个 parent ,每个 parent 有 3 个 child 。

parents: [
 {
   "id": 1
   "childIds": {1,3,5}
 },
 {
   "id": 2
   "childIds": {2,4,6}
 }
]

作为 fetcher 的结果,我将有 2 个请求:

  1. childDataLoader.loadMany({1,3,5})

  2. childDataLoader.loadMany({2,4,6})

在 Dataloader 中它将只有一个(如预期的那样),但请查看 ID 的顺序(我无法控制它):

childService.findByIds({1,3,5,2,4,6})

在输出中我将收到:

"data": {
    "parents": [
      { 
        "id": 1,
        "childs": [
          {
            "id": 1,
          },
          {
            "id": 2,
           },
          {
            "id": 3,
           }
       },
      { 
        "id": 2,
        "childs": [
          {
            "id": 4,
          },
          {
            "id": 5,
           },
          {
            "id": 6,
           }
       }
      ]
     }
   ]
}

最佳答案

你回答的顺序必须和请求的顺序一样, 如果 ORM 对 sql 响应进行了排序,则在收到 ORM 的响应后将其返回到 DataLoader 中,例如:

 private BatchLoader<Long, Child> buildBatchLoader() {
   return list -> CompletableFuture.supplyAsync(() -> 
                   childService.findByIds(list).stream()
                     .sorted(Comparator.comparingLong(entity -> 
                             list.indexOf(entity.getId())))
                     .collect(Collectors.toList()));
 };   
    
         
                     

关于java - DataLoader批量加载bug(MyBatis、JavaEE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63630507/

相关文章:

java - 使用 Java 为视障人士放大屏幕

java - 在 Java 7 中编译使用 Java 8 类型的方法

graphql - 在 Graphql 请求中发送双引号和反斜杠

java - 通过 Jersey 的 JAX-RS -> HTTP 正文中没有返回内容(方法完成没有错误)

java - 如何指示从 Jersey 中的 REST 服务保存到浏览器的文件名?

java - 在服务器上运行单元测试(JAX-RS)

java - 在 TextView 中将字符串的一部分设为粗体

java - 如何使用 ProductFlavors 来定义 App 中的开发行为?

python - 如何使用 graphene-file-upload 和 apollo-upload-client 将 graphql 中的文件上传到 Python 数据库并在前端使用react。

vue.js - 结果、Vue、Apollo 和 GraphQL 缺少属性