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:
- Get DB connection
- Open TX
- Do blocking IO stuff
- Close TX
- 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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…