from:http://javatar.iteye.com/blog/981787
關(guān)于Dubbo服務(wù)框架的分布式事務(wù),雖然現(xiàn)在不急著做,但可以討論一下。 

我覺(jué)得事務(wù)的管理不應(yīng)該屬于Dubbo框架, 
Dubbo只需實(shí)現(xiàn)可被事務(wù)管理即可, 
像JDBC和JMS都是可被事務(wù)管理的分布式資源, 
Dubbo只要實(shí)現(xiàn)相同的可被事務(wù)管理的行為,比如可以回滾, 
其它事務(wù)的調(diào)度,都應(yīng)該由專門的事務(wù)管理器實(shí)現(xiàn)。 

在Java中,分布式事務(wù)主要的規(guī)范是JTA/XA, 
其中:JTA是Java的事務(wù)管理器規(guī)范, 
XA是工業(yè)標(biāo)準(zhǔn)的X/Open CAE規(guī)范,可被兩階段提交及回滾的事務(wù)資源定義, 
比如某數(shù)據(jù)庫(kù)實(shí)現(xiàn)了XA規(guī)范,則不管是JTA,還是MSDTC,都可以基于同樣的行為對(duì)該數(shù)據(jù)庫(kù)進(jìn)行事務(wù)處理。 

在JTA/XA中,主要有兩個(gè)擴(kuò)展點(diǎn): 

(1) TransactionManager 
JTA事務(wù)管理器接口,實(shí)現(xiàn)該接口,即可完成對(duì)所有XA資源的事務(wù)調(diào)度,比如BEA的Tuxedo,JBossJTA等。 

(2) XAResource 
XA資源接口,實(shí)現(xiàn)該接口,即可被任意TransactionManager調(diào)度,比如:JDBC的XAConnection,JMS的XAMQ等。 

而Dubbo的遠(yuǎn)程服務(wù),也應(yīng)該是一個(gè)XAResource,比如:XAInvoker和XAExporter, 
Dubbo只需在第一次提交時(shí),將請(qǐng)求發(fā)到服務(wù)提供方進(jìn)行緩存和寫盤, 
在第二次提交時(shí),再基于緩存調(diào)用服務(wù)的Impl實(shí)現(xiàn), 
當(dāng)然一些健狀性分支流程要考慮清楚。 

JTA/XA的基本原理如下: 

 

1. 用戶啟動(dòng)一個(gè)事務(wù): 
Java代碼  收藏代碼
  1. transactionManager.begin();   


2. 事務(wù)管理器在當(dāng)前線程中初始化一個(gè)事務(wù)實(shí)例: 
Java代碼  收藏代碼
  1. threadLocal.set(new TransactionImpl());  


3. 用戶調(diào)用JDBC或JMS或Dubbo請(qǐng)求,請(qǐng)求內(nèi)部初始化一個(gè)XAResource實(shí)例: 
Java代碼  收藏代碼
  1. XAResource xaResource = new XAResourceImpl(); // 比如:XAConnection  


4. JDBC或JMS或Dubbo內(nèi)部從當(dāng)前線程獲取事務(wù): 
Java代碼  收藏代碼
  1. Transaction transaction = transactionManager.getTransaction(); // 其內(nèi)部為:threadLocal.get();  


5. 將當(dāng)前XAResource注冊(cè)到事務(wù)中: 
Java代碼  收藏代碼
  1. transaction.enlistResource(xaResource);  


6. 用戶提交一個(gè)事務(wù): 
Java代碼  收藏代碼
  1. transactionManager.commit(); // 其內(nèi)部為:getTransaction().commit();  


7. 事務(wù)for循環(huán)調(diào)用所有注冊(cè)的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. }  


8. 當(dāng)然,還有一些異常流程,比如rollback和forget等。 

舉例: 
Java代碼  收藏代碼
  1. TransactionManager transactionManager = ...; // 從JNDI進(jìn)行l(wèi)ookup等方式獲取  
  2. transactionManager.begin(); // 啟動(dòng)事務(wù)  
  3. try {  
  4.     jdbcConn.executeUpdate(sql); // 執(zhí)行SQL語(yǔ)句,DB寫入binlog,但不更新表  
  5.     jmsMQ.send(message); // 發(fā)送消息,MQ記錄消息,但不進(jìn)入隊(duì)列  
  6.     dubboService.invoke(parameters); // 調(diào)用遠(yuǎn)程服務(wù),Provider緩存請(qǐng)求信息,但不執(zhí)行  
  7.     transactionManager.commit(); // 提交事務(wù),數(shù)據(jù)庫(kù),消息隊(duì)列,遠(yuǎn)程服務(wù)同時(shí)提交  
  8. catch(Throwable t) {  
  9.     transactionManager.rollback(); // 回滾事務(wù),數(shù)據(jù)庫(kù),消息隊(duì)列,遠(yuǎn)程服務(wù)同時(shí)回滾  
  10. }