如何设计全局分布式事务(无数据库)?JTA 是否可以用于无数据库事务?

2022-09-03 02:03:33

我认为这是一个相当普遍的问题:如何将我的业务逻辑放在分布式系统环境中的全局事务中?举个例子,我有一个包含几个子任务的 TaskA:

TaskA {subtask1, subtask2, subtask3 ... }

这些子任务中的每一个都可以在本地机器或远程机器上执行,我希望TaskA通过事务以原子方式(成功或失败)执行。每个子任务都有一个回滚函数,一旦 TaskA 认为操作失败(因为其中一个子任务失败),它就会调用子任务的每个回滚函数。否则,TaskA 将提交整个事务。

为此,我遵循“审计试用”事务模式为每个子任务提供记录,以便 TaskA 可以知道子任务的操作结果,然后决定回滚或提交。这听起来很简单,但是,困难的部分是如何将每个子任务与全局事务相关联?

当 TaskA 开始时,它会启动一个全局事务,该子任务对此一无所知。为了让子任务意识到这一点,我必须将事务上下文传递给子任务的每次调用。这真是太可怕了!我的子任务可以在新线程中执行,也可以通过AMQP代理发送消息在远程执行,很难巩固上下文传播的方式。

我做了一些研究,如“事务模式 - 四个事务相关模式的集合”,“异步消息传递环境中的已检查事务”,这些都不能解决我的问题。他们要么没有实际的例子,要么没有解决上下文传播问题。

我想知道人们如何解决这个问题?因为这种交易在企业软件中必须很常见。

X/Open XA 只是解决方案吗?JTA可以在这里提供帮助吗(我还没有研究JTA,因为它的大多数内容都与数据库事务有关,而且我正在使用Spring,我不想在我的软件中涉及另一个Java EE应用程序服务器)。

一些专家可以与我分享一些想法吗?谢谢。

结论

Arjan和Martin给出了非常好的答案,谢谢。最后,我没有走这条路。经过更多的研究,我选择了另一种模式“CheckPoint1

在查看我的要求时,我发现我打算“审核试用事务模式”是知道操作已进入哪个级别,如果失败,我可以在重新加载一些上下文后在失败的位置重新启动它。实际上这不是事务,它没有在失败后回滚其他成功步骤。这是 CheckPoint 模式的本质。然而,学习分布式事务的东西让我学到了很多有趣的东西。除了Arjan和Martin提到的。我还建议深入研究这个领域的人看看CORBA,它是分布式系统的一个众所周知的协议。


答案 1

你是对的,由于 JTA API 提供的 XA 事务管理器,您需要两阶段提交支持。

据我所知,Spring本身不提供事务管理器实现。JtaTransactionManager 仅委托给通常由 JavaEE 实现提供的现有实现。

因此,您必须将JTA实现插入Spring才能有效地完成工作。以下是一些建议:

然后,必须实现资源管理器以支持两阶段提交。在 JavaEE 世界中,它由打包为 RAR 归档的资源适配器组成。根据资源的类型,需要读取/实现以下方面:

例如,我建议您查看经典“文件事务”问题的实现:


答案 2

如果要编写自己的事务资源,确实需要实现 XAResource 并让它加入正在进行的事务,处理来自事务管理器的准备和提交请求等。

数据源是最知名的事务资源,但如前所述,它们并不是唯一的。您已经提到了 JMS 提供程序。各种缓存解决方案(例如Infinispan)也是事务资源。

实现XAResources并使用JTA API的较低级别部分以及更低级别的JTS(Java事务服务)并不是胆小者的任务。API可能过时,整个过程很少被记录下来。

原因是常规企业应用程序创建自己的事务资源极为罕见。事务性的全部意义在于执行对外部观察者具有原子性的操作。

在绝大多数情况下可观察意味着操作的效果存在于数据库中。几乎每个数据源都已经是事务性的,因此该用例已完全涵盖。

另一个可观察到的效果是消息是否已发送,并且现有消息传递解决方案也完全涵盖了这一点。

最后,更新内存映射(集群范围)是另一个可观察到的效果,主要缓存提供程序也涵盖了这一效果。

在与外部企业信息系统 (EIS) 一起运行时,对事务效应的需求仍然存在,根据经验,此类系统的供应商提供事务感知连接器。

剩下的用例的颤抖是如此之小,以至于显然没有人真正费心去写太多关于它的文章。有一些博客涵盖了一些基础知识,但很多事情将留给你自己的实验。

如果您真的绝对需要走这条路,并且现有的事务资源之一无法满足您的需求,请尝试自己验证。


推荐