如何用graphql-jpa java解决graphql n + 1问题?

sha*_*aks 3 graphql-java

n+1在我的一个应用程序中面临graphql 问题,我在java中使用带有restful webservice的graphql.我使用schemagen-graphqlspring-data-jpa用于连接到我的Oracle数据库.我看到了很多帖子,但大部分答案都是graphql-node.js实施.任何与java相关的东西都会很好.

kaq*_*qao 11

我不太了解schemagen-graphql这里是否重要,但总的来说,目前有两种选择graphql-java:

  1. 使用DataFetcher和注释您的数据提取器DataFetchingFieldSelectionSet.
    这个选项更容易理解和使用,但LocalContext在处理空值时会与您联系并且不完全遵守规范.
    遗憾的是文档记录很差(并且最近被弃用了),但归结为:
    1. 使用注释@Batched方法BatchedExecutionStrategy
    2. 在该数据获取器中,BatchedExecutionStrategy将始终返回源对象列表(而不是一个).
    3. 这样的数据获取器必须始终返回结果列表(与源列表长度相同).这允许以简单方式批量加载对象.一个明显的例子是立即从关系数据库加载许多行:
List<Article> articles = DataFetchingEnvironment.getSource(); //source is a list
List<Long> authorIds = articles.stream.map(article -> article.getAuthodId()).collect(Collectors.toList());

//fetch all the authors in one go    
`SELECT * FROM Author WHERE author_id IN (authorIds)`
Run Code Online (Sandbox Code Playgroud)
  1. 使用DataFetcher#get,而不是直接取取它的数据.这个想法与原始数据加载器JavaScript库非常相似.@Batched如果你走这条路,一定要注册.仅适用于默认值DataFetchingEnvironment#getSource,仅适用于查询(因此不要指望它适用于突变和订阅).该选项已有详细记录,应该是首选,尽管更难以使用.

我认为使用它的最佳方式(不需要Spring或类似的框架)是存储DataLoader在共享上下文中:

DataLoaderRegistry loaders = ...; //initialize your loaders, usually per request

graphQL.execute(ExecutionInput.newExecutionInput()
         .query(operation)
         .dataLoaderRegistry(loaders) //add the registry to input
         .build()); 
Run Code Online (Sandbox Code Playgroud)

然后在您的AsyncExecutionStrategy身上,您可以DataLoaderRegistry 通过ExecutionInput以下方式获得所需:

return env.getDataLoader("authors").load(article.getAuthorId());
Run Code Online (Sandbox Code Playgroud)

作为旁注,您可能需要查看我自己的库,以便从Java,GraphQL-SPQR生成GraphQL API .这是使用它的最小演示DataFetcher.

对于DataLoader,逻辑与上面相同,并且您注入了DataLoadervia DataFetchingEnvironment#getDataLoader(String dataLoaderName)注释:

@GrapgQLQuery
public CompletableFuture<Author> author(@GraphQLContext Article article, @GraphQLEnvironment ResolutionEnvironment env) {
    return env.dataFetchingEnvironment.getDataLoader("authors").load(article.getAuthorId())
}
Run Code Online (Sandbox Code Playgroud)