graphql java中文文档_graphql-java使用手册:part6 使用 Dataloader

使用 Dataloader

使用 graphql, 你很可能会去查询图结构的数据(graph of data )

(这可能是句废话).

如果用简单直接的方法去获取每个field的数据,可能会效率很低。

使用 java-dataloader 可以帮助你更有效地缓存和批量化数据加载操作。

>><

假设我们用以下的 StarWars 查询。这查询了一个英雄(

hero)和他朋友的名字,和他朋友的朋友的名字。很多时候,他们有共同的朋友。

{

hero {

name

friends {

name

friends {

name

}

}

}

}

下面是查询的结果。你可以看到,Han, Leia, Luke 和 R2-D2

是一群紧密的朋友。他们有很多共同的朋友。

[hero: [name: 'R2-D2', friends: [

[name: 'Luke Skywalker', friends: [

[name: 'Han Solo'], [name: 'Leia Organa'], [name: 'C-3PO'], [name: 'R2-D2']]],

[name: 'Han Solo', friends: [

[name: 'Luke Skywalker'], [name: 'Leia Organa'], [name: 'R2-D2']]],

[name: 'Leia Organa', friends: [

[name: 'Luke Skywalker'], [name: 'Han Solo'], [name: 'C-3PO'], [name: 'R2-D2']]]]]

]

一个直接的实现是为每个人物对象(person object)调用一次 DataFetcher

去获取数据。

这样你需要 15 次网络调用 。即使这群有有很多相同的朋友。使用

dataloader 可以让 graphql 查询更高效。

因 graphql 会批量化每个层级的查询。 ( 如先是 hero 之后是 friends

之后是他们的 friends), Data loader 返回了一个 ”

期约(promise)”,期约会返回一个 person

object.(人物对象)。在查询的每个层级, dataloader.dispatch()

方法均会被调用一次,以获取真实的数据。当开启了缓存功能时

(默认开启),将直接返回之前加载过的 person,而不会再发起一次查询。

上例中,共有 5 个独立的 people。但当缓存和批量化开启后,只发起了 3

次调用 batch loader 方法的查询操作。*3* 次网络或DB访问,当然比 15

次牛B多了。【译者补】

如果你使用了如 java.util.concurrent.CompletableFuture.supplyAsync()

的异步程序方式 。多个field的远程加载数据就可以并发进行了。.

这可以让查询更快,因一次并发了多个远程调用。

下面就是示例代码:

// a batch loader function that will be called with N or more keys for batch loading

BatchLoader characterBatchLoader = new BatchLoader() {

@Override

public CompletionStage> load(List keys) {

//

// we use supplyAsync() of values here for maximum parellisation

//

return CompletableFuture.supplyAsync(() -> getCharacterDataViaBatchHTTPApi(keys));

}

};

// a data loader for characters that points to the character batch loader

DataLoader characterDataLoader = new DataLoader<>(characterBatchLoader);

//

// use this data loader in the data fetchers associated with characters and put them into

// the graphql schema (not shown)

//

DataFetcher heroDataFetcher = new DataFetcher() {

@Override

public Object get(DataFetchingEnvironment environment) {

return characterDataLoader.load("2001"); // R2D2

}

};

DataFetcher friendsDataFetcher = new DataFetcher() {

@Override

public Object get(DataFetchingEnvironment environment) {

StarWarsCharacter starWarsCharacter = environment.getSource();

List friendIds = starWarsCharacter.getFriendIds();

return characterDataLoader.loadMany(friendIds);

}

};

//

// DataLoaderRegistry is a place to register all data loaders in that needs to be dispatched together

// in this case there is 1 but you can have many

//

DataLoaderRegistry registry = new DataLoaderRegistry();

registry.register("character", characterDataLoader);

//

// this instrumentation implementation will dispatch all the dataloaders

// as each level fo the graphql query is executed and hence make batched objects

// available to the query and the associated DataFetchers

//

DataLoaderDispatcherInstrumentation dispatcherInstrumentation

= new DataLoaderDispatcherInstrumentation(registry);

//

// now build your graphql object and execute queries on it.

// the data loader will be invoked via the data fetchers on the

// schema fields

//

GraphQL graphQL = GraphQL.newGraphQL(buildSchema())

.instrumentation(dispatcherInstrumentation)

.build();

需要注意的是,只有你使用了 DataLoaderDispatcherInstrumentation

,上面说的才会生效。由它来调用 dataLoader.dispatch() 。不然,期约(

promises ) 将不会被执行,就更不会有数据获取了。

查询范围的 Data Loaders

对于 Web

请求,请求的结果可能会因不同用户而不同的。如果是特定用户的数据,你一定不希望用户A的数据,被用户B查询到。

所以 DataLoader 实例的范围很重要。这时,你需要对每个 Request

创建一个新的 DataLoader,来保证它只在当前请求中生效。

如果你需要的是不同请求间共享数据,所以你会希望 DataLoader

的生命周期更长。

但如用你用请求级的 data loaders ,为每个请求创建 GraphQL and

DataLoader 是花费很少资源的。Its the GraphQLSchema creation that can

be expensive, especially if you are using graphql SDL parsing.

i在代码中静态引用 schema 。可以是静态变量或 IoC

单件组件。但每次处理请求时,都需要创建 GraphQL 对象。

GraphQLSchema staticSchema = staticSchema_Or_MayBeFrom_IoC_Injection();

DataLoaderRegistry registry = new DataLoaderRegistry();

registry.register("character", getCharacterDataLoader());

DataLoaderDispatcherInstrumentation dispatcherInstrumentation

= new DataLoaderDispatcherInstrumentation(registry);

GraphQL graphQL = GraphQL.newGraphQL(staticSchema)

.instrumentation(dispatcherInstrumentation)

.build();

graphQL.execute("{ helloworld }");

// you can now throw away the GraphQL and hence DataLoaderDispatcherInstrumentation

// and DataLoaderRegistry objects since they are really cheap to build per request

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值