Spring Transaction Management 是否适用于 Spring WebFlux?

Spring对RDBMS事务管理的支持是否也适用于Spring WebFlux?

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

如果事务管理确实有效,那么方法是否实际和异常,或者 或 返回类型必须发出错误信号?@TransactionalthrowMonoFlux

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

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

我的组织有WebFlux和Cassandra的经验,但Cassandra有一个原生的响应式驱动程序。

谢谢!


答案 1

编辑:这个答案不再适用于Spring框架版本5.2 M2及更高版本。请参阅此文章。感谢杜邦@Florent提到这一点。

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

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

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

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

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

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

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

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

所有这些都在阻塞线程上的一个代码块中。

这将更安全(无泄漏)并且更易于理解。此外,由于您基本上自己完成所有操作,因此可以选择哪种错误处理最适合您的方案。


答案 2

@Transactional现在在 Spring Reactive 上有效。

我不会在这里详细介绍。一切都在这篇文章中解释:https://spring.io/blog/2019/05/16/reactive-transactions-with-spring


推荐