Distributed Transaction Patterns

Distributed Transaction Patterns

This tech tip explores some patterns for distributed transactions.
Suppose you have two processes (A and B) on two different machines. How can you ensure reliability of tasks that span these two processes? In other words: how can you make sure that there is no partial work done by A (but not by B) or the other way around. Depending on what you want and the nature of your application, there are different ways of doing this. This tech tip explains the most common solutions.

**SOLUTION 1: Request/reply with transaction propagation
SOLUTION 2: JMS with XA drivers
SOLUTION 3: JMS with transaction propagation
SOLUTION 4: TCC
SOLUTION 1: Request/reply with transaction propagation**

This solution applies to RMI-IIOP or web service (SOAP) scenarios.

In this approach, you would do the following:

Use Transactions in each process.
A starts a transaction before calling B.
Process A ships the propagation of the transaction along with each remote call to B.
B imports the transaction before processing the call.
B processes the call.
B terminates the imported transaction and returns the Extent to A.
A adds the extent to its local transaction.
A instructs commit or rollback of the distributed transaction.
This ensures that both A and B either commit or rollback the same way.

Another approach would be to use JMS, as explained next.

SOLUTION 2: JMS with XA drivers

In this approach, the calls from A to B are done by JMS messages. This is done as explained below.

To send a message to B, A does the following:

A starts a transaction.
A sends a JMS message to B, and uses XA JMS drivers to do so.
A commits the transaction.
On the other side, B receives a message as follows:

B starts a transaction (or uses the Atomikos JMS session to do this automatically).
B consumes the JMS message.
B commits the transaction (or lets the Atomikos JMS session do this).
This pattern also ensures reliability, but should be used only under the following conditions:

The JMS is used in persistent mode.
A delay is acceptable between processing at A and processing at B.
When A sends the message to B, it is already certain that the message can be processed at B.
A does not expect a reply from B before committing its transaction.
The first condition is required to avoid message loss after A commits. The second condition is needed because JMS is asynchronous in nature. The third condition ensures that B will eventually be able to process the message. The fourth condition is due to the fact that JMS can’t receive a reply to a message that is sent within the same transaction.

For shared database situations between A and B: make sure to send (from A to B) via a different AtomikosConnectionFactoryBean, or (alternatively) make sure to send to B in a subtransaction. Otherwise, B might receive the message before A’s database updates are committed… Also see Documentation.CommitOrderingWithJms for details.
SOLUTION 3: JMS with transaction propagation

This approach works similar to the first (RMI-IIOP) approach, except that JMS messages are used instead of RMI calls. In this case, the JMS messages can be either persistent or non-persistent, and the acknowledgement mode should NOT be transactional (meaning that non-XA, regular JMS drivers should be used and messages should be sent with either AUTO ACKNOWLEDGE or EXPLICIT ACKNOWLEDGE settings. If this is true then the following will work:

Use Transactions in each process.
A starts a transaction before sending a message to B.
Process A ships the propagation of the transaction along with each JMS message to B.
B imports the transaction before processing the message.
B processes the message.
B terminates the imported transaction and returns the Extent to A in a reply message.
A adds the extent to its local transaction.
A instructs commit or rollback of the distributed transaction.
SOLUTION 4: TCC

TCC is the most loosely-coupled solution with virtually guaranteed operability for Service Oriented Architectures. If you want to know more then checkout TransactionsForSOA.

### MySQL 不支持分布式事务的原因 MySQL 的核心设计目标之一是提供高性能和易用性,因此其架构并未原生支持复杂的分布式事务管理功能。分布式事务涉及多个数据库实例之间的协调操作,这通常会引入额外的开销并降低性能[^1]。由于 MySQL 主要面向单机环境优化,在多节点场景下缺乏内置的支持机制来处理两阶段提交(Two-Phase Commit, 2PC)协议或其他类似的复杂事务控制逻辑。 此外,MySQL 的存储引擎体系结构也对其支持分布式事务的能力产生了影响。尽管 InnoDB 存储引擎提供了 ACID 特性和本地事务支持,但它并不直接集成用于跨数据库实例同步状态的功能模块[^3]。 ### 解决方案概述 针对上述局限性,可以采用以下几种方法实现对分布式事务的需求: #### 方法一:通过 XA 协议扩展 MySQL 支持基于标准 X/Open XA 规范定义的接口,允许应用程序利用外部事务管理器执行分布式的原子操作序列。此方式依赖于客户端库以及中间件层配合完成整个流程中的准备、提交或回滚动作。然而需要注意的是,启用该特性可能会带来一定的资源消耗,并且并非所有的驱动程序都完全兼容这一标准。 ```sql -- Example SQL commands demonstrating usage of XA Transactions in MySQL. XA START 'transaction_id'; INSERT INTO table_name (column) VALUES ('value'); XA END 'transaction_id'; XA PREPARE 'transaction_id'; XA COMMIT 'transaction_id'; -- Or rollback depending upon application logic. ``` #### 方法二:借助第三方工具和服务 除了依靠数据库自身的功能外,还可以考虑部署专门设计用来解决这类问题的产品或者框架。例如 Atomikos 和 Bitronix 是两个流行的开源 Java EE 连接池解决方案,它们能够帮助开发者更方便地构建具备全局一致性保障的应用系统;而像 Oracle Tuxedo 或 IBM WebSphere Transaction such services 则属于商业级选项[^4]。 另外值得注意的一点在于现代微服务架构趋势下越来越多的企业倾向于放弃传统意义上的强一致性的分布式事务模型转而探索最终一致性模式下的补偿措施比如 Saga Pattern 等替代方案从而达到简化运维成本提高灵活性的目的同时满足业务需求水平上的容忍度范围内的结果准确性要求[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值