Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Spring Transaction Management Work with Spring WebFlux?

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!

like image 779
user3303372 Avatar asked Dec 26 '18 16:12

user3303372


People also ask

Does Spring support transaction management?

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.

What does Spring declarative transaction management work with?

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.

Which servers are used to support Spring transactions?

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.

Why is ChainedTransactionManager deprecated?

We recommend to not use ChainedTransactionManager as it emulates distributed transactions without providing consistency guarantees that can end up in partially committed transactions.


1 Answers

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:

  1. Get DB connection
  2. Open TX
  3. Do blocking IO stuff
  4. Close TX
  5. Close/release DB connection

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.

like image 105
Liviu Ilea Avatar answered Oct 09 '22 08:10

Liviu Ilea