使用 graphql-spring 的 LazyInitializationException [英] LazyInitializationException with graphql-spring

查看:24
本文介绍了使用 graphql-spring 的 LazyInitializationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在将我的 REST-Server 迁移到 GraphQL(至少部分迁移).大部分工作已经完成,但我偶然发现了这个我似乎无法解决的问题:graphql 查询中的 OneToMany 关系,使用 FetchType.LAZY.

I am currently in the middle of migrating my REST-Server to GraphQL (at least partly). Most of the work is done, but i stumbled upon this problem which i seem to be unable to solve: OneToMany relationships in a graphql query, with FetchType.LAZY.

我正在使用:https://github.com/graphql-java/graphql-spring-boothttps://github.com/graphql-java/graphql-java-tools 用于集成.

I am using: https://github.com/graphql-java/graphql-spring-boot and https://github.com/graphql-java/graphql-java-tools for the integration.

这是一个例子:

实体:

@Entity
class Show {
   private Long id;
   private String name;

   @OneToMany(mappedBy = "show")
   private List<Competition> competition;
}

@Entity
class Competition {
   private Long id;
   private String name;

   @ManyToOne(fetch = FetchType.LAZY)
   private Show show;
}

架构:

type Show {
    id: ID!
    name: String!
    competitions: [Competition]
}

type Competition {
    id: ID!
    name: String
}

extend type Query {
    shows : [Show]
}

解析器:

@Component
public class ShowResolver implements GraphQLQueryResolver {
    @Autowired    
    private ShowRepository showRepository;

    public List<Show> getShows() {
        return ((List<Show>)showRepository.findAll());
    }
}

如果我现在用这个(速记)查询查询端点:

If i now query the endpoint with this (shorthand) query:

{
  shows {
    id
    name
    competitions {
      id
    }
  }
}

我明白了:

org.hibernate.LazyInitializationException: 延迟初始化失败角色集合:Show.competitions,无法初始化代理 -没有会话

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Show.competitions, could not initialize proxy - no Session

现在我知道为什么会发生这个错误以及它意味着什么,但我真的不知道是否要对此应用修复.我不想让我的实体急切地获取所有关系,因为这会抵消 GraphQL 的一些优势.我可能需要寻找解决方案的任何想法?谢谢!

Now i know why this error happens and what it means, but i don't really know were to apply a fix for this. I don't want to make my entites to eagerly fetch all relations, because that would negate some of the advantages of GraphQL. Any ideas where i might need to look for a solution? Thanks!

推荐答案

我解决了这个问题,我想应该更仔细地阅读 graphql-java-tools 库的文档.除了解决基本查询的 GraphQLQueryResolver 之外,我还需要一个 GraphQLResolver 用于我的 Show 类,如下所示:

I solved it and should have read the documentation of the graphql-java-tools library more carefully i suppose. Beside the GraphQLQueryResolver which resolves the basic queries i also needed a GraphQLResolver<T> for my Showclass, which looks like this:

@Component
public class ShowResolver implements GraphQLResolver<Show> {
    @Autowired
    private CompetitionRepository competitionRepository;

    public List<Competition> competitions(Show show) {
        return ((List<Competition>)competitionRepository.findByShowId(show.getId()));
    }
}

这告诉库如何解析我的 Show 类中的复杂对象,并且仅在初始查询请求包含 Competition 对象时使用.新年快乐!

This tells the library how to resolve complex objects inside my Showclass and is only used if the initially query requests to include the Competitionobjects. Happy new Year!

EDIT 31.07.2019:我从此离开了下面的解决方案.长时间运行的事务很少是一个好主意,在这种情况下,一旦您扩展应用程序,它就会导致问题.我们开始实现 DataLoaders 以异步方式批量查询.长时间运行的事务与 DataLoader 的异步性质相结合可能导致死锁:https://github.com/graphql-java-kickstart/graphql-java-tools/issues/58#issuecomment-398761715(有关更多信息,请参阅上方和下方).我不会删除下面的解决方案,因为对于较小的应用程序和/或不需要任何批处理查询的应用程序来说,它可能仍然是一个很好的起点,但在这样做时请记住此注释.

EDIT 31.07.2019: I since stepped away from the solution below. Long running transactions are seldom a good idea and in this case it can cause problems once you scale your application. We started to implement DataLoaders to batch queries in an async matter. The long running transactions in combination with the async nature of the DataLoaders can lead to deadlocks: https://github.com/graphql-java-kickstart/graphql-java-tools/issues/58#issuecomment-398761715 (above and below for more information). I will not remove the solution below, because it might still be good starting point for smaller applications and/or applications which will not need any batched queries, but please keep this comment in mind when doing so.

根据这里的要求,是另一种使用自定义执行策略的解决方案.我正在使用 graphql-spring-boot-startergraphql-java-tools:

As requested here is another solution using a custom execution strategy. I am using graphql-spring-boot-starter and graphql-java-tools:

创建一个 ExecutionStrategy 类型的 Bean 来处理事务,像这样:

Create a Bean of type ExecutionStrategy that handles the transaction, like this:

@Service(GraphQLWebAutoConfiguration.QUERY_EXECUTION_STRATEGY)
public class AsyncTransactionalExecutionStrategy extends AsyncExecutionStrategy {

    @Override
    @Transactional
    public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
        return super.execute(executionContext, parameters);
    }
}

这会将查询的整个执行放在同一个事务中.我不知道这是否是最佳解决方案,而且它在错误处理方面也已经存在一些缺点,但您不需要那样定义类型解析器.

This puts the whole execution of the query inside the same transaction. I don't know if this is the most optimal solution, and it also already has some drawbacks in regards to error handling, but you don't need to define a type resolver that way.

请注意,如果这是唯一的 ExecutionStrategy Bean,它也将用于突变,这与 Bean 名称可能暗示的相反.见 https://github.com/graphql-java-kickstart/graphql-spring-boot/blob/v11.1.0/graphql-spring-boot-autoconfigure/src/main/java/graphql/kickstart/spring/web/boot/GraphQLWebAutoConfiguration.java#L161-L166 供参考.为了避免这种情况,请定义另一个用于突变的 ExecutionStrategy:

Notice that if this is the only ExecutionStrategy Bean present, this will also be used for mutations, contrary to what the Bean name might suggest. See https://github.com/graphql-java-kickstart/graphql-spring-boot/blob/v11.1.0/graphql-spring-boot-autoconfigure/src/main/java/graphql/kickstart/spring/web/boot/GraphQLWebAutoConfiguration.java#L161-L166 for reference. To avoid this define another ExecutionStrategy to be used for mutations:

@Bean(GraphQLWebAutoConfiguration.MUTATION_EXECUTION_STRATEGY)
public ExecutionStrategy queryExecutionStrategy() {
    return new AsyncSerialExecutionStrategy();
}

这篇关于使用 graphql-spring 的 LazyInitializationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆