【发布时间】:2020-12-17 04:39:54
【问题描述】:
我的生产中有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)后如何解析实体的方式。所以我决定我应该有一些排序,所以我实现了它,但它并没有解决问题。
例如: 我有 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 个父母,每个人有 3 个孩子。
parents: [
{
"id": 1
"childIds": {1,3,5}
},
{
"id": 2
"childIds": {2,4,6}
}
]
作为 fetcher 的结果,我将有 2 个请求:
-
childDataLoader.loadMany({1,3,5}) -
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,
}
}
]
}
]
}
【问题讨论】:
-
通常根据 input-ids 的顺序对 childService#findByIds 的结果进行排序应该可以解决问题。你确定 input-id 列表的顺序已经搞砸了吗?您是否使用调试器进行了验证?
-
是的,我用调试器验证了它,现在对 sql 响应的排序很有帮助
-
如果我尝试像这样进行 smt:
childService.findByIds(list).thenApply(listEntityes -> { long count = listEntityes.stream() .filter(entitye -> !listIds.contains(.(entitye .getId()))).count(); if (count > 0) { throw new Exception("Different sql request and response"); } return it; });我会得到一个异常 -
如果在 CompletableFuture.supplyAsync(() -> childService.findByIds(list)); 中设置断点,列表的顺序是否仍然正确?
-
我想我找到了解决方案,我也有一些遗漏的排序,这破坏了 DataLoader 的顺序。会检查,如果是,我会改变我的问题并提供答案
标签: java graphql jax-rs mybatis java-ee-7