http://javatar.iteye.com/blog/981787

 

关于Dubbo服务框架的分布式事务,虽然现在不急着做,但可以讨论一下。

我觉得事务的管理不应该属于Dubbo框架,
Dubbo只需实现可被事务管理即可,
像JDBC和JMS都是可被事务管理的分布式资源,
Dubbo只要实现相同的可被事务管理的行为,比如可以回滚,
其它事务的调度,都应该由专门的事务管理器实现。

在Java中,分布式事务主要的规范是JTA/XA,
其中:JTA是Java的事务管理器规范,
XA是工业标准的X/Open CAE规范,可被两阶段提交及回滚的事务资源定义,
比如某数据库实现了XA规范,则不管是JTA,还是MSDTC,都可以基于同样的行为对该数据库进行事务处理。

在JTA/XA中,主要有两个扩展点:

(1) TransactionManager
JTA事务管理器接口,实现该接口,即可完成对所有XA资源的事务调度,比如BEA的Tuxedo,JBossJTA等。

(2) XAResource
XA资源接口,实现该接口,即可被任意TransactionManager调度,比如:JDBC的XAConnection,JMS的XAMQ等。

而Dubbo的远程服务,也应该是一个XAResource,比如:XAInvoker和XAExporter,
Dubbo只需在第一次提交时,将请求发到服务提供方进行缓存和写盘,
在第二次提交时,再基于缓存调用服务的Impl实现,
当然一些健状性分支流程要考虑清楚。

JTA/XA的基本原理如下:

5c17f55f-3ad6-3a20-bcba-2cf23cecfc1d.jpg

1. 用户启动一个事务:

Java代码

  1. transactionManager.begin();   

transactionManager.begin(); 



2. 事务管理器在当前线程中初始化一个事务实例:

Java代码

  1. threadLocal.set(new TransactionImpl());  

threadLocal.set(new TransactionImpl());



3. 用户调用JDBC或JMS或Dubbo请求,请求内部初始化一个XAResource实例:

Java代码 复制代码

  1. XAResource xaResource = new XAResourceImpl(); // 比如:XAConnection  

XAResource xaResource = new XAResourceImpl(); // 比如:XAConnection



4. JDBC或JMS或Dubbo内部从当前线程获取事务:

Java代码 复制代码

  1. Transaction transaction = transactionManager.getTransaction(); // 其内部为:threadLocal.get();  

Transaction transaction = transactionManager.getTransaction(); // 其内部为:threadLocal.get();



5. 将当前XAResource注册到事务中:

Java代码 复制代码

  1. transaction.enlistResource(xaResource);  

transaction.enlistResource(xaResource);



6. 用户提交一个事务:

Java代码 复制代码

  1. transactionManager.commit(); // 其内部为:getTransaction().commit();  

transactionManager.commit(); // 其内部为:getTransaction().commit();



7. 事务for循环调用所有注册的XAResource的两阶段提交:

Java代码 复制代码

  1. Xid xid = new XidImpl();   

  2. for (XAResource xaResource: xaResources) {   

  3. xaResource.prepare(xid);   

  4. xaResource.commit(xid, true);   

  5. xaResource.commit(xid, false);   

  6. }  

Xid xid = new XidImpl();
for (XAResource xaResource: xaResources) {
xaResource.prepare(xid);
xaResource.commit(xid, true);
xaResource.commit(xid, false);
}



8. 当然,还有一些异常流程,比如rollback和forget等。

举例:

Java代码 复制代码

  1. TransactionManager transactionManager = ...; // 从JNDI进行lookup等方式获取   

  2. transactionManager.begin(); // 启动事务   

  3. try {   

  4.     jdbcConn.executeUpdate(sql); // 执行SQL语句,DB写入binlog,但不更新表   

  5.     jmsMQ.send(message); // 发送消息,MQ记录消息,但不进入队列   

  6.     dubboService.invoke(parameters); // 调用远程服务,Provider缓存请求信息,但不执行   

  7.     transactionManager.commit(); // 提交事务,数据库,消息队列,远程服务同时提交   

  8. catch(Throwable t) {   

  9.     transactionManager.rollback(); // 回滚事务,数据库,消息队列,远程服务同时回滚   

  10. }  

TransactionManager transactionManager = ...; // 从JNDI进行lookup等方式获取
transactionManager.begin(); // 启动事务
try {
    jdbcConn.executeUpdate(sql); // 执行SQL语句,DB写入binlog,但不更新表
    jmsMQ.send(message); // 发送消息,MQ记录消息,但不进入队列
    dubboService.invoke(parameters); // 调用远程服务,Provider缓存请求信息,但不执行
    transactionManager.commit(); // 提交事务,数据库,消息队列,远程服务同时提交
} catch(Throwable t) {
    transactionManager.rollback(); // 回滚事务,数据库,消息队列,远程服务同时回滚
}