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

Posted

技术标签:

【中文标题】如何使用 graphql-jpa java 解决 graphql n+1 问题?【英文标题】:How to resolve graphql n+1 issue with graphql-jpa java? 【发布时间】:2018-05-20 09:00:11 【问题描述】:

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

【问题讨论】:

【参考方案1】:

我不太了解schemagen-graphql 以及它在这里是否重要,但总的来说,graphql-java 目前有 3 个选项:

    在解析父字段时(即在父字段的DataFetcher 中)预取您需要的内容。您可以通过检查DataFetchingFieldSelectionSet 来准确查看请求的子字段。 如果预取的数据不适合结果对象,您可以将其存储在LocalContext 中,并在解析子字段值时使用它。 this blog post 很好地解释了这种方法。 使用 deprecated(如果您使用 graphql.execution 下的类)或 实验性(如果使用 graphql.execution.nextgen 下的类)方法来注释您的数据使用@Batched 和使用BatchedExecutionStrategy 的提取器。 此选项易于理解和使用,但会将您与BatchedExecutionStrategy 联系起来(旧版本在处理空值时并未完全遵守规范)。 遗憾的是,它的记录很差,但归结为:
      @Batched注释DataFetcher#get方法 在该数据提取器中,DataFetchingEnvironment#getSource 将始终返回源对象列表(而不是一个)。 此类数据获取器必须始终返回结果列表(与源列表长度相同)。这允许以简单的方式批量加载对象。一个明显的例子是一次从关系数据库中加载许多行:
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)
    使用DataLoader 获取您的数据,而不是直接获取它。这个想法与最初的数据加载器 javascript 库非常相似。仅适用于默认的 AsyncExecutionStrategy 并且仅适用于查询(因此不要期望它适用于突变和订阅)。

您可以在ExecutionInput 中提供DataLoaderRegistry 的实例,并且您通常希望在每个请求上重新创建数据加载器和注册表(如果它们是无状态的,可以共享批处理加载器):

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

graphQL.execute(ExecutionInput.newExecutionInput()
         .query(operation)
         .dataLoaderRegistry(loaders) //add the registry to input
         .build()); 

然后在您的DataFetcher 中,您可以随时访问DataLoader 你需要通过DataFetchingEnvironment#getDataLoader(String dataLoaderName):

return env.getDataLoader("authors").load(article.getAuthorId());

作为旁注,您可能想查看我自己的库,用于从 Java 生成 GraphQL API,GraphQL-SPQR。这是 a minimal demonstration 使用 @Batched 的方法。

DataLoader,逻辑同上,通过@GraphQLEnvironment注解到DataLoaderRegistry

@GrapgQLQuery
public CompletableFuture<Author> author(@GraphQLContext Article article, @GraphQLEnvironment ResolutionEnvironment env) 
    return env.dataFetchingEnvironment.getDataLoader("authors").load(article.getAuthorId())

我可能还会添加一个专门的注释,例如@DataLoader("authors"),用于直接注入加载器。

【讨论】:

以上是关于如何使用 graphql-jpa java 解决 graphql n+1 问题?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 java.net.SocketException:使用 selenium 的 java 中的连接重置异常?

如何在使用 JSch SFTP 库时解决 Java UnknownHostKey?

如何解决这个错误发生在包selenium使用java?

java高并发,如何解决,啥方式解决,高并发

第一个java程序中文乱码以及如何解决

如何解决java.lang.OutOfMemoryError