-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spring @Transactional support #448
Comments
I'm not 100% sure but i think |
Spring GraphQL uses a Once a Because of this arrangement, it is impossible to declare a global transaction via e.g. You see an increased number of queries because that's what happens here. Looking up references by their identifier is recommended to avoid lazy-loading issues. However, that approach comes at the cost of additional queries. JPA implementations typically optimize to some extent using You could de-proxy any objects within your Spring GraphQL and the GraphQL engine can leverage reactive programming and asynchronous execution patterns, making it impossible to have ThreadLocal transactions out of the box as we cannot make any assumptions over the actual thread on which a call is being made. |
Not that I think that would be a solution on its own, but aren't there database clients for spring that support transactions over reactive streams? Also; thanks for the extensive response. |
There is reactive transaction support, but since there is no |
Isn't the entrypoint where the |
No, the entry point is the |
A more concrete sample or snippets of schema types, entity objects, and controller methods would help. If it is only a |
Keep in mind that even then, there is no single Reactor chain since GraphQL's |
If the data fetchers are tied to the request, and the request received something like multiple mutations or even nested queries wouldn't it be possible to wrap the entire request in a transaction? |
We've had an internal discussion. The recent upgrade of our context propagation in #459 provides some new capabilities that make it easier to propagate context across data fetchers, and not only from the transport level to data fetchers. What we need to investigate are some options to hook into the start and end of a transaction. For example if A single For |
According to the graphql spec mutations are supposed to be processed in isolation, so I don't think there should be something running them in a single transaction. |
One possible way to solve it could be setting custom |
You can actually configure it, by defining a @Bean
GraphQlSourceBuilderCustomizer configurer(PlatformTransactionManager platformTransactionManager) {
var executionStrategy = new TransactionalExecutionStrategy(platformTransactionManager, new SimpleDataFetcherExceptionHandler());
return builder ->
builder.configureGraphQl(
graphQl ->
graphQl
.mutationExecutionStrategy(executionStrategy)
.queryExecutionStrategy(executionStrategy));
} Unfortunately I couldn't find a nice way to get the Spring provided |
Using JPA for GraphQL Queries is a tricky business to make it work around transactional boundaries with lazy JPA proxy initializations for entity attributes. You can take a look at the GraphQL Query Api for JPA Entity Models project that solves this problem and many other JPA Query problems, i.e. N+1, search criteria, batch loading, large query result streaming, etc.. I successfully integrated it with |
I also encountered this problem when using
|
When we first started with spring we used JPA and made heavy use of its relational support. This caused some issues with spring-graphql because sometimes lazy associations were accessed in a field resolver, causing an error that said something like "there isn't an active transaction".
We worked around this by writing a custom instrumentation to start a transaction for every query and mutation.
Now that's we removed all associations (in preparation of migrating to R2DBC), we no longer need this transaction by default. But removing this instrumentation somehow causes a significant increase in queries.
Adding
@Transactional
to graphql controllers doesn't seem to make a difference. Also adding@Transactional
to a parent controller, and@Transactional(propagation = Propagation.MANDATORY)
to controller of an underlying type controller, causes the execution to fail with:This seems odd to me, because I would expect a transaction to exist there because of the transaction started in the parent controller.After some discussion with a teammate I've realized this isn't odd, because both controllers are invoked separately by the datafetchers, and thus not sharing the transaction. It still would be very welcome to have a solution for this.Is there any support for transactions in Spring Graphql? Or is using a custom instrumentation (or
ExecutionStrategy
) the only way out for this?The text was updated successfully, but these errors were encountered: