gpt4 book ai didi

java - 具有 Spring Boot 和事务边界的 graphql-spqr

转载 作者:行者123 更新时间:2023-12-02 08:49:35 25 4
gpt4 key购买 nike

我们正在将 graphql-spqr 和 graphql-spqr-spring-boot-starter 用于一个新项目(使用 Spring DataJPA、hibernate 等)。

我们有这样的突变:

@Transactional
@GraphQLMutation
public Match createMatch(@NotNull @Valid MatchForm matchForm) {
Match match = new Match(matchForm.getDate());
match.setHomeTeam(teamRepository.getOne(matchForm.getHomeId()));
match.setAwayTeam(teamRepository.getOne(matchForm.getAwayId()));
match.setResult(matchForm.getResult());
matchRepository.save(match);
return match;
}

这个突变工作得很好:

mutation createMatch ($matchForm: MatchFormInput!){   
match: createMatch(matchForm: $matchForm) {
id
}
variables: {...}

我省略了变量,因为它们并不重要。如果我将其更改为:

mutation createMatch ($matchForm: MatchFormInput!){   
match: createMatch(matchForm: $matchForm) {
id
homeTeam {
name
}
}
variables: {...}

我收到 LazyInitalizationException,我知道为什么:

homeTeam 由 ID 引用并由 teamRepository 加载。返回的团队只是一个 hibernate 代理。这对于保存新的比赛来说很好,不需要更多。但为了发回结果,GraphQL 需要访问代理并调用 match.team.getName()。但这显然发生在用 @Transactional 标记的事务之外。

我可以用以下方法修复它 团队 homeTeam teamRepository.findById(matchForm.getHomeId()).orElse(null); match.setHomeTeam(homeTeam);

Hibernate 不再加载代理,而是加载真实对象。但由于我不知道 GraphQL 查询到底要求什么,如果以后不需要的话,急切地加载所有数据是没有意义的。如果 GraphQL 在 @Transactional 内执行,那就太好了,这样我就可以为每个查询和突变定义事务边界。

对此有什么建议吗?

PS:我剥离了代码并进行了一些清理以使其更加简洁。因此代码可能无法运行,但确实说明了问题。

最佳答案

@kaqqao 的回答非常好,但我想对此发表评论并展示第三种解决方案:

  1. 我不喜欢这个解决方案,因为我必须在我真的不关心的环境中做很多工作。这不是 GraphQL 的目的。如果需要,应该进行解决。展望每个 GraphQL 查询以及路径的各个方向,对我来说听起来很奇怪。

  2. 我设法通过服务类来实现这一点。但是您会遇到异常问题,因为异常被包装并且未正确处理。

    public class TransactionalGraphQLExecutor implements GraphQLServletExecutor {
    private final ServletContextFactory contextFactory;
    @Autowired(required = false)
    @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    private DataLoaderRegistryFactory dataLoaderRegistryFactory;

    private final TxGraphQLExecutor txGraphQLExecutor;

    public TransactionalGraphQLExecutor(ServletContextFactory contextFactory, TxGraphQLExecutor txGraphQLExecutor) {
    this.contextFactory = contextFactory;
    this.txGraphQLExecutor = txGraphQLExecutor;
    }

    @Override
    public Map<String, Object> execute(GraphQL graphQL, GraphQLRequest graphQLRequest, NativeWebRequest nativeRequest) {
    ExecutionInput executionInput = buildInput(graphQLRequest, nativeRequest, contextFactory, dataLoaderRegistryFactory);
    if (graphQLRequest.getQuery().startsWith("mutation")) {
    return txGraphQLExecutor.executeReadWrite(graphQL, executionInput);
    } else {
    return txGraphQLExecutor.executeReadOnly(graphQL, executionInput);
    }
    }

    }

    public class TxGraphQLExecutor  { 
    @Transactional
    public Map<String, Object> executeReadWrite(GraphQL graphQL, ExecutionInput executionInput) {
    return graphQL.execute(executionInput).toSpecification();
    }

    @Transactional(readOnly = true)
    public Map<String, Object> executeReadOnly(GraphQL graphQL, ExecutionInput executionInput) {
    return graphQL.execute(executionInput).toSpecification();
    }

    }

  • 也可以进行检测,请参阅 https://spectrum.chat/graphql/general/transactional-queries-with-spring~47749680-3bb7-4508-8935-1d20d04d0c6a

  • 目前我最喜欢的是拥有另一个手动解析器

     @GraphQLQuery
    @Transactional(readOnly = true)
    public Team getHomeTeam(@GraphQLContext Match match) {
    return matchRepository.getOne(match.getId()).getHomeTeam();
    }
  • 当然你也可以设置spring.jpa.open-in-view=false(反模式)

  • 或者您可以急切地获取。

  • 如果您可以使用 GraphQL 定义事务边界,那就太好了。

    关于java - 具有 Spring Boot 和事务边界的 graphql-spqr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60873340/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com