如何使用 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-graphql
和 spring-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 中的连接重置异常?