Java:许multithreading中的XA事务传播

如何在Java SE(非Java EE或Spring)中使用事务管理器(如Bitronix , JBoss TS或Atomikos )来支持以下用例:

我们假设我们有以下类:

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> futures = new ArrayList<Future>(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或任何其他multithreading环境:

 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()方法保持并发(因为它将同时访问多个数据库)和事务性。

这似乎可以使用SubTxThread使用Atomikos完成

 //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(); } 

XA规范要求所有XA调用都在同一个线程上下文中执行。 详细说明其原因,因为可以在任何事务分支甚至在您的线程中创建之前调用提交。

如果您只对如何在JBoss TS中的XA事务中执行这三个调用感兴趣

首先确保您的-ds.xml将数据源指定为

 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的支持。 可能是一个红鲱鱼,但如果你没有时间紧缩,它可能值得研究。

你呢

  1. BEGIN_TRANSATION:连接到您服务中的所有3个数据库,
  2. 将Connection对象(而不是db对象)传递给MyRunnable
  3. END_TRANSACTION:调用提交并关闭服务中的所有3个连接