Spring事务管理可以与Spring WebFlux一起使用吗?

use*_*372 7 java spring spring-data-jpa spring-webflux

Spring对RDBMS事务管理的支持在Spring WebFlux中是否也起作用?

例如,假设配置正确,带有@Transactional注释的方法是否会使用Spring事务管理器并在发生错误时回滚事务?

如果事务管理确实起作用,那么@Transactional方法是否必须实际throw和异常,或者必须是MonoFlux返回类型发出错误信号?

我知道JDBC本质上是阻塞的,因此任何JDBC操作都必须从阻塞过渡到反应性,反之亦然。

Spring事务管理器通过使用ThreadLocal(对吗?)工作,我假设它在Reactor环境中不起作用,因为Reactor在线程方面很节俭,并且在第一个线程正在等待时,一个线程可以将一个工作单元换成另一个工作单元在I / O上。我知道Reactor的Context对象在概念上类似于ThreadLocal(对吗?),但是我还没有看到任何文档提到该事务使用了它。另外,事务中发生的所有JDBC操作都必须使用相同的操作,Connection这在响应式上下文中可能很难做到。

我的组织具有WebFlux和Cassandra的经验,但是Cassandra具有本机响应式驱动程序。

谢谢!

Flo*_*ont 9

@Transactional现在在 Spring Reactive 上有效。

我这里就不详细说了。这篇文章中解释了一切: https: //spring.io/blog/2019/05/16/reactive-transactions-with-spring


Liv*_*lea 7

编辑:此答案不再适用于 Spring Framework 5.2 M2 及更高版本。请参阅这篇文章。谢谢@Florent Dupont 提到这一点。

AFAIK Spring 标准事务管理不适用于 WebFlux。

使用@Transactional将不起作用,因为当调用带注释的方法时,事务机制将ThreadLocal在调用线程的内部保存事务的状态。正如你自己所说,这是行不通的。它阻塞并共享状态。

但是,您可以使用 a.runOn(Schedulers.parallel())将阻塞代码发送到另一个线程。通过这种方式,您可以拥有一个带有可阻塞线程的线程池,您可以将其配置为与数据库连接池具有相同的大小。

但即便如此,您仍然不能依赖,@Transactional因为线程池重用线程的方式。在标准的 Servlet 架构中,每个 HTTP 请求都有一个线程。当响应被发回时,线程停止,从而关闭事务。但在这种情况下,Reactor 调度程序不会关闭线程并将它们重用于其他事件。因此,即使您可以阻止,您仍然会遇到与以前相同的问题。

您确实有Context您提到的选项,我认为这适用于Mono. 我不确定它是否适用于Flux(我认为 Flux 中的所有事件共享相同的上下文,这是您不想要的)。

另一种选择是使用 Touple2T1作为业务对象和T2事务上下文。我不能推荐这个,因为你将业务逻辑与技术内容混合在一起,它会使事情变得过于复杂。

我最好的选择是自己进行交易/连接管理:

  1. 获取数据库连接
  2. 打开TX
  3. 做阻塞 IO 的事情
  4. 关闭交易
  5. 关闭/释放数据库连接

全部在一个阻塞线程上的一个代码块中。

这将更安全(无泄漏)且更易于理解。此外,因为您基本上可以自己做所有事情,所以您可以选择最适合您的场景的错误处理类型。