Reference Site:
atomikos site: http://www.atomikos.com/Documentation/ConfiguringJdbc
http://www.atomikos.com/Documentation/WebHome
JTA : http://java.sun.com/javaee/5/docs/tutorial/doc/bnciy.html#bnciz
XA: http://jroller.com/pyrasun/category/XA
XADataSource 通过四步Start, End, Prepare, Commit 保证 多个数据源的事务完整性. 它主要额外提供了Prepare这个过程. 那么提供这个Prepare过程有什么用呢?这个过程有两个很重要的步骤, 1. 询问每个DataSource 你准备好了Commit吗? 在这个期间,如果有任何一个Datasource返回No,所有事务回滚. 2. 向系统内写日志.(这一步对于在Commit的时候产生异常进行灾难性的恢复相当关键)。这里需要强调的是,对于XADataSource,JTA的事务管理范围包括 Start, End, Prepare 这三个步骤.
如果我们有2个数据源数据源A和数据源B, 来讨论如下几种事务失败的情况.
1. 在 Start <--> End(Java Transaction boundary) 之间, 凡是有任何异常,均可以正常回滚.
2. 在 Prepare 的时候出错, Java 的业务逻辑 处理完成, XADataSource现在会询问所有的 DataSource "are you ready to commit", 如果任何一个DataSource说"No", 所有DataSource的事务全部回滚.
在 项目开发的时候,遇到过一个很有趣的例子, 两个数据源 远程MQ Server + 本地DB2 DataBase, 用的atomikos JTA. 这里,我故意把atomikos的XADataSource 换成了Hibernate 的DataSource,写了一段很简单的程序,先执行Database 的存取操作,然后将相关数据发送给MQ,我故意在程序执行的最后(随便写了段System.out.println()语句) 处打了个断点,然后用Debug模式执行到该断点处,然后我扒开网线,这个时候实际上MQ已经失效了,然后让程序继续执行,最后MQ事务显然失败,但是数据库的事务却提交了. 这里的问题很明显,首先第一,我没用XADataSource,而用的Hibernate的DataSource,所以不会有Prepare这一步。第二,这个例子中,Start <--> END 已经执行完成,对于不是XADataSource的 JTA会直接到 Commit。而这步实际上就是在Commit 的时候出的错. 在JTA的范围之外了,所以整个事务回滚不了. 如果我们将Hibernate的DataSource换成atomikos的XADataSource,然后用相同的操作执行上面的步骤,MQ和DB2事务都失败. 这正是因为在Commit之前会有一步Prepare的过程,XADataSource会询问 MQ Server 和 DB2 DataSource 你们准备好了吗?而此时,MQ会说NO,所以整个事务回滚。这里,我们可以看到XADataSource 的必要性。
3. 在Commit 的时候出错. 这步就是灾难性的一步了,也是XADataSource最棘手的地方了。试想,JTA执行过程中一切成功,并且在Prepare过程的时候,所有的数据源都回答OK。最后某个DataSource在Commit自己的数据的时候不幸出错. 那么此时该如何解决呢? 这里普片的做法就是在Prepare的时候,让XADataSource写日记记录数据提交的详细记录。那么是如何操作的呢? XADatasource会针对每个 XADataSource实例 记录一个编号, 在Prepare的时候会针对这个XADataSource实例写日志,并且保留Commit失败时候的日志,如果Commit的时候发生异常 (我们知道,这步已经是JTA事务管理之外的了,换句话说,这里是XADataSource 的JTA 已经不可能回滚的了),之后 atmokios 根据该失败的XADataSource实例日志 会定期检查对应处理失败的数据源是否恢复正常,如果恢复正常,那么它会根据日志将进行再次提交,直到成功为止。 但是现在并不是任何 XADataSource 的 Provider 都提供了Prepare()过程写日志的功能,有些 仅仅是商业版本的才会提供。或许是因为这步是最棘手也是最难实现的的部分吧.