Does Spring's support for RDBMS transaction management also work in Spring WebFlux?
For example, assuming proper configuration, will a method annotated with the @Transactional
annotation use the Spring transaction manager and rollback the transaction if an error occurs?
If transaction management does work, must a @Transactional
method actually throw
and exception, or must the Mono
or Flux
return type emit an error signal?
I know JDBC is inherently blocking, and thus any JDBC operations must be bridged from blocking to reactive, or vice-versa.
The Spring transaction manager works by using a ThreadLocal
(right?) which I'm assuming won't work in a Reactor environment, since Reactor is frugal with threads and a single thread can swap out one unit of work for another while the first is waiting on I/O. I know Reactor has the Context
object which is conceptually similar to ThreadLocal
(right?) but I haven't seen any documentation that mentions that transaction makes use of it. Additionally, all JDBC operations that occur within a transaction must use the same Connection
which might be tough to do in a reactive context.
My organization has experience with WebFlux and Cassandra, but Cassandra has a native reactive driver.
Thank you!
Spring supports both programmatic and declarative transaction management. EJBs require an application server, but Spring transaction management can be implemented without the need of an application server.
Unlike EJB CMT, which is tied to JTA, the Spring Framework's declarative transaction management works in any environment. It can work with JDBC, JDO, Hibernate or other transactions under the covers, with configuration changes only.
Spring supports distributed transactions through WebLogic Server's JTA implementation. You can also configure the Spring transaction manager to delegate responsibility to the WebLogic Server JTA transaction manager.
We recommend to not use ChainedTransactionManager as it emulates distributed transactions without providing consistency guarantees that can end up in partially committed transactions.
EDIT: This answer is not valid anymore for Spring Framework version 5.2 M2 and higher. See this article. Thank you @Florent Dupont for mentioning this.
AFAIK the Spring standard transaction management does not work with WebFlux.
Using the @Transactional
will not work because when an annotated method is called, the transaction mechanism will save the state of the transaction inside the ThreadLocal
of the calling thread. As you have said it yourself, this does not work. It blocks AND it shares state.
However, you can use a .runOn(Schedulers.parallel())
in order to send the blocking code to another thread. This way you can have a thread pool with blockable threads which you can configure to have the same size as you DB connection pool.
But even so you still cannot rely on @Transactional
because of the way the tread pool reuses the threads. In a standard Servlet architecture you have one thread per HTTP request. When the response is sent back, the thread is stopped, which closes the transaction. In this case though, the Reactor scheduler does not close the threads and reuses them for other events. So even if you CAN block you still have the same problem as before.
You do have the Context
option you've mentioned and I think this would work for Mono
. I'm not sure if it would work for a Flux
(I'm thinking that all events in a Flux share the same context, which is what you don't want).
Another option is to use a Touple2 with T1
as the business object and T2
the transaction context. I cannot recommend this though since you mix business logic with technical stuff and it overcomplicates things.
My best bet would be to do the transaction/connection management yourself:
all in one code block on a blocking thread.
This will be safer (no leaks) and easier to understand. Also because you basically do everything yourself, you can chose what kind of error handling works best for your scenario.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With