2011-03-12 21 views
4

如何使用一個事務管理器(如BitronixJBoss TSAtomikos)在Java SE(非Java EE或Spring)來支持以下使用案例:Java的:多個線程中的XA事務傳播

讓我們假設我們有以下類:

public class Dao { 

    public void updateDatabase(DB db) { 
     connet to db 
     run a sql 
    } 

} 

,我們從創建一個Java Runnable接口,如下所示:在鄰

public class MyRunnable extends Runnable { 

    Dao dao; 
    DB db; 

    public MyRunnable(Dao dao, DB db) { 
     this.dao=dao; 
     this.db = db; 
    }   

    public run() throws Exception { 
     return dao.updateDatabase(db); 
    } 
} 

現在烏爾服務層,我們有另一個類:

public class Service { 

    public void updateDatabases() { 

     BEGIN TRANSACTION; 

     ExecutorService es = Executors.newFixedThreadPool(10); 

     ExecutorCompletionService ecs = new ExecutorCompletionService(es); 

     List<Future<T>> futures = new ArrayList<Future<T>>(n); 

     Dao dao = new Dao(); 

     futures.add(ecs.submit(new MyRunnable(dao, new DB("db1"))); 
     futures.add(ecs.submit(new MyRunnable(dao, new DB("db2"))); 
     futures.add(ecs.submit(new MyRunnable(dao, new DB("db3"))); 

     for (int i = 0; i < n; ++i) { 
      completionService.take().get(); 
     } 

     END TRANSACTION; 
    } 

} 

客戶端可以是一個Servlet或任何其他多線程環境:

public MyServlet extend HttpServlet { 

    protected void service(final HttpServletRequest request, final HttpServletResponse response) throws IOException { 

     Service service = new Service(); 

     service.updateDatabases(); 

    } 

} 

什麼是正確的代碼BEGIN TRANSACTION和END TRANSACTION部分?這是否可行?如果不是,需要改變什麼?要求是保持updateDatabases()方法併發(因爲它將同時訪問多個數據庫)和事務性。

回答

2

好像這是可以做到使用Atomikos使用SubTxThread

//first start a tx 
TransactionManager tm = ... 
tm.begin(); 

Waiter waiter = new Waiter(); 

//the code that calls the first EIS; defined by you 
SubTxCode code1 = ... 

//the associated thread 
SubTxThread thread1 = new SubTxThread (waiter , code1); 

//the code that calls the second EIS; defined by you 
SubTxCode code2 = ... 

//the associated thread 
SubTxThread thread2 = new SubTxThread (waiter , code2); 

//start each thread 
thread1.start(); 

thread2.start(); 

//wait for completion of all calls 
waiter.waitForAll(); 

//check result 
if (waiter.getAbortCount() == 0) { 
    //no failures -> commit tx 
    tm.commit(); 
} else { 
    tm.rollback(); 
} 
1

XA規範要求所有的XA調用在同一個線程上下文中執行。詳細說明其原因,因爲在您的線程中甚至可以創建任何事務分支之前就可以調用提交。

如果你是如何在XA事務中的JBoss TS執行這些三個調用

首先確保只關心你的-ds.xml指定你的數據源作爲<xa-datasource>

InitialContext ctx = new InitialContext(parms); 
UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction"); 

ut.begin(); 

//Some Transactional Code 

ut.commit(); 

記住與上面的代碼將無法使用ExecutorService來並行化調用。

邊注意:我不太瞭解它,但JTS/OTS聲稱允許多個線程共享一個事務。我認爲它是通過傳播類似於ws-coordination/ws-transaction的事務上下文來實現的,並且由JBossTS支持。可能是一條紅色的鯡魚,但如果你的時間不緊張,可能值得研究。

+0

即使bean產生線程,EJB是否仍保持事務性,如下所示?由於J2EE規範實際上禁止來自產卵線程的資源適配器以外的組件,我相當懷疑它。 –

+1

我的錯你是對的這是來自JBoss TS文檔 - 看起來XA規範本身要求整個事務在一個線程中進行。「X/Open XA接口指定必須從同一個線程上下文中調用與事務關聯相關的XA調用。」 – nsfyn55

0

你怎麼樣

  1. BEGIN_TRANSATION:連接到您的服務的所有3個數據庫,
  2. 通過連接對象(而不是的db對象)到MyRunnable
  3. END_TRANSACTION:調用提交併關閉所有3個連接的 您的服務