Java Transaction API (JTA) specifies standard Java interfaces between a transaction manager and the parties involved in a distributed transaction system: the resource manager, the application server, and the transactional applications.java
JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可使用JTA来访问事务。 sql
JTA容许应用程序执行分布式事务处理--在两个或多个网络计算机资源上访问而且更新数据,这些数据能够分布在多个数据库上。JDBC驱动程序的JTA支持极大地加强了数据访问能力。 数据库
位于javax.transaction包中编程
a、UserTransaction接口:让应用程序得以控制事务的开始、挂起、提交、回滚等。由Java客户端程序或EJB调用。
b、TransactionManager 接口:用于应用服务器管理事务状态
c、Transaction接口:用于执行相关事务操做
d、XAResource接口:用于在分布式事务环境下,协调事务管理器和资源管理器的工做
e、Xid接口:为事务标识符的Java映射服务器
注:前3个接口位于Java EE版的类库 javaee.jar 中,Java SE中没有提供!UserTransaction是编程经常使用的接口。JTA只提供了接口,没有具体的实现。网络
若是使用 JTA 界定事务,那么就须要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序才能够参与 JTA 事务。 架构
一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection 是参与 JTA 事务的 JDBC 链接。要使用JTA事务,必须使用XADataSource来产生数据库链接,产生的链接为一个XA链接。 app
XA链接(javax.sql.XAConnection)和非XA(java.sql.Connection)链接的区别在于: nosql
XA能够参与JTA的事务,并且不支持像JDBC那样的自动提交。 分布式
同时,应用程序必定不要对 XA 链接调用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() 。相反,应用程序应该使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() 。
注意: Oracle, Sybase, DB2, SQL Server等大型数据库才支持XA, 支持分布事务。 MySQL属于Non-XA。
Java Transaction API 容许您操做应用程序中的分布式事务(Distributed Transaction)。JTA 中有一组方法,它将传统的 JDBC 调用封装到了两阶段提交(Two-Phase-Commit)协议中。
在异构环境中,您一般会发现一个事务管理器(Transaction Manager),负责处理分布式事务。(实际上,事务管理器能够完成大量的工做负载平衡。)所以,不只存在到数据库的直接链接,还有到事务管理器 (Transaction Manager)的链接。这就是 JTA 发挥做用的地方:JTA 是 Java 应用程序和事务管理器(Transaction Manager)之间的接口。下图演示了一个包含分布式事务的典型环境。
因为存在事务管理器(Transaction Manager),它一般包含在应用程序服务器(Application Server)中,就再也不有两层(Two-Tier)架构。传统的客户/服务器(Client/Server)架构已经由三层(Tree-Tier)架构 所取代,三层架构包含应用程序/客户机、事务管理器(Transaction Manager)/应用程序服务器(Application Server)和数据库服务器,而数据库服务器通常称做XA Resource。
一般,应用程序服务器(Application Server)提供了应用程序可使用的多种服务。在谈到分布式事务时,该服务就称做XA Resource。固然,在应用程序可使用 XA Resource 以前,首先要在应用程序服务器中注册和配置 XA Resource。
如今,若是您计划在应用程序中使用 JTA,就必须修改代码,以便还能够与应用程序服务器(Application Server)进行通讯。这包括一些附加的方法调用和指定的错误/异常处理
在谈到 XA 规范以前,必须首先了解分布式事务处理( Distributed Transaction Processing , DTP )的概念。 Transaction ,即事务,又称之为交易,指一个程序或程序段,在一个或多个资源如 数据库 或文件上为完成某些功能的执行过程的集合。
分布式事务处理是指一个事务可能涉及多个数据库操做,分布式事务处理的关键是必须有一种方法能够知道事务在任何地方所作的全部动做,提交或回滚事务的决定必须产生统一的结果(所有提交或所有回滚)。
X/Open 组织(即如今的 Open Group )定义了分布式事务处理模型。
X/Open DTP 模型( 1994 )包括:应用程序( AP )、事务管理器( TM )、资源管理器( RM )、通讯资源管理器( CRM )四部分。通常,常见的事务管理器( TM )是交易中间件,常见的资源管理器( RM )是数据库,常见的通讯资源管理器( CRM )是消息中间件。
一般把一个数据库内部的事务处理,如对多个表的操做,做为本地事务看待。数据库的事务处理对象是本地事务,而分布式事务处理的对象是全局事务。
所谓全局事务,是指分布式事务处理环境中,多个数据库可能须要共同完成一个工做,这个工做便是一个全局事务,例如,一个事务中可能更新几个不一样的数据库。对数据库的操做发生在系统的各处,但必须所有被提交或回滚。此时一个数据库对本身内部所作操做的提交不只依赖自己操做是否成功,还要依赖与全局事务相关的其它数据库的操做是否成功,若是任一数据库的任一操做失败,则参与此事务的全部数据库所作的全部操做都必须回滚。
通常状况下,某一数据库没法知道其它数据库在作什么,所以,在一个 DTP 环境中,交易中间件是必需的,由它通知和协调相关数据库的提交或回滚。而一个数据库只将其本身所作的操做(可恢复)影射到全局事务中。
XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数)。交易中间件用它来通知数据库事务的开始、结束以及提交、回滚等。XA 接口函数由数据库厂商提供。
XA协议包括两套函数,以xa_开头的及以ax_开头的。
如下的函数使事务管理器能够对资源管理器进行的操做:
1)xa_open,xa_close:创建和关闭与资源管理器的链接。
2)xa_start,xa_end:开始和结束一个本地事务。
3)xa_prepare,xa_commit,xa_rollback:预提交、提交和回滚一个本地事务。
4)xa_recover:回滚一个已进行预提交的事务。
5)ax_开头的函数使资源管理器能够动态地在事务管理器中进行注册,并能够对XID(TRANSACTION IDS)进行操做。
6)ax_reg,ax_unreg;容许一个资源管理器在一个TMS(TRANSACTION MANAGER SERVER)中动态注册或撤消注册。
JTA能够处理任何提供符合XA接口的资源。包括:JDBC链接,数据库,JMS,商业对象等等。
一般状况下,交易中间件与数据库经过 XA 接口规范,使用两阶段提交来完成一个全局事务, XA 规范的基础是两阶段提交协议。
第一阶段:交易中间件请求全部相关数据库准备提交(预提交)各自的事务分支,以确认是否全部相关数据库均可以提交各自的事务分支。
当某一数据库收到预提交后,若是能够提交属于本身的事务分支,则将本身在该事务分支中所作的操做固定记录下来,并给交易中间件一个赞成提交的应答,此时数 据库将不能再在该事务分支中加入任何操做,但此时数据库并无真正提交该事务,数据库对共享资源的操做还未释放(处于上锁状态)。若是因为某种缘由数据库 没法提交属于本身的事务分支,它将回滚本身的全部操做,释放对共享资源上的锁,并返回给交易中间件失败应答。
第二阶段:交易中间件审查全部数据库返回的预提交结果,如全部数据库均可以提交,交易中间件将要求全部数据库作正式提交,这样该全局事务被提交。而若是有任一数据库预提交返回失败,交易中间件将要求全部其它数据库回滚其操做,这样该全局事务被回滚。
以一个全局事务为例, AP 首先通知交易中间件开始一个全局事务,交易中间件经过 XA 接口函数通知数据库开始事务,而后 AP 能够对数据库管理的资源进行操做,数据库系统记录事务对本地资源的全部操做。操做完成后交易中间件经过 XA 接口函数通知数据库操做完成。交易中间件负责记录 AP 操做过哪些数据库(事务分支)。 AP 根据状况通知交易中间件提交该全局事务,交易中间件会经过 XA 接口函数要求各个数据库作预提交,全部数据库返回成功后要求各个数据库作正式提交,此时一笔全局事务结束。
XA 规范对应用来讲,最大好处在于事务的完整性由交易中间件和数据库经过 XA 接口控制, AP 只须要关注与数据库的应用逻辑的处理,而无需过多关心事务的完整性,应用设计开发会简化不少。
具体来讲,若是没有交易中间件,应用系统须要在程序内部直接通知数据库开始、结束和提交事务,当出现异常状况时必须由专门的程序对数据库进行反向操做才能完成回滚。若是是有不少事务分支的全局事务,回滚时状况将变得异常复杂。而使用 XA 接口,则全局事务的提交是由交易中间件控制,应用程序只需通知交易中间件提交或回滚事务,就能够控制整个事务(可能涉及多个异地的数据库)的所有提交或回滚,应用程序彻底不用考虑冲正逻辑。
在一个涉及多个数据库的全局事务中,为保证全局事务的完整性,由交易中间件控制数据库作两阶段提交是必要的。但 典型的两阶段提交,对数据库来讲事务从开始到结束(提交或回滚)时间相对较长,在事务处理期间数据库使用的资源(如逻辑日志、各类锁),直到事务结束时才 会释放。所以,使用典型的两阶段提交相对来讲会占用更多的资源,在网络条件不是很好,如低速网、网络颠簸频繁,状况会更为严重。
当一个全局事务只涉及一个数据库时,有一种优化方式,即一阶段提交。当 AP 通知交易中间件提交事务时,交易中间件直接要求数据库提交事务,省去两阶段提交中的第一阶段,能够缩短处理一个事务的时间,以提升事务处理的效率。做为两 阶段提交的一种特例,与两阶段同样,一阶段提交也是标准的。
In an XA implementation, the transaction manager commits the distributed branches of a global transaction by using a two-phase commit protocol.
In phase one, the transaction manager directs each resource manager to prepare to commit, which is to verify and guarantee it can commit its respective branch of the global transaction. If a resource manager cannot commit its branch, the transaction manager rolls back the entire transaction in phase two.
In phase two, the transaction manager either directs each resource manager to commit its branch or, if a resource manager reported it was unable to commit in phase one, rolls back the global transaction.
Note the following optimizations:
If a global transaction is determined by the transaction manager to have involved only one branch, it skips phase one and commits the transaction in phase two.
If a global transaction branch is read-only, where it does not generate any transaction log records, the transaction manager commits the branch in phase one and skips phase two for that branch.
Note:
The transaction manager considers the global transaction committed if and only if all branches successfully commit.
在分布式系统中,事务每每包含有多个参与者的活动,单个参与者上的活动是可以保证原子性的,而多个参与者之间原子性的保证则须要经过两阶段提交来实现,两阶段提交是分布式事务实现的关键。
很明显,两阶段提交保证了分布式事务的原子性,这些子事务要么都作,要么都不作。而数据库的一致性是由数据库的完整性约束实现的,持久性则是经过 commit日志来实现的,不是由两阶段提交来保证的。至于两阶段提交如何保证隔离性,能够参考Large-scale Incremental Processing Using Distributed Transactions and Notifications中两阶段提交的具体实现。
两阶段提交的过程涉及到协调者和参与者。协调者能够看作成事务的发起者,同时也是事务的一个参与者。对于一个分布式事务来讲,一个事务是涉及到多个参与者的。具体的两阶段提交的过程以下:
第一阶段:
首先,协调者在自身节点的日志中写入一条的日志记录,而后全部参与者发送消息prepare T,询问这些参与者(包括自身),是否可以提交这个事务;
参与者在接受到这个prepare T 消息之后,会根据自身的状况,进行事务的预处理,若是参与者可以提交该事务,则会将日志写入磁盘,并返回给协调者一个ready T信息,同时自身进入预提交状态状态;若是不能提交该事务,则记录日志,并返回一个not commit T信息给协调者,同时撤销在自身上所作的数据库改;
参与者可以推迟发送响应的时间,但最终仍是须要发送的。
第二阶段:
协调者会收集全部参与者的意见,若是收到参与者发来的not commit T信息,则标识着该事务不能提交,协调者会将Abort T 记录到日志中,并向全部参与者发送一个Abort T 信息,让全部参与者撤销在自身上全部的预操做;
若是协调者收到全部参与者发来prepare T(ready T)信息,那么协调者会将Commit T日志写入磁盘,并向全部参与者发送一个Commit T信息,提交该事务。若协调者迟迟未收到某个参与者发来的信息,则认为该参与者发送了一个VOTE_ABORT信息,从而取消该事务的执行。
参与者接收到协调者发来的Abort T信息之后,参与者会终止提交,并将Abort T 记录到日志中;若是参与者收到的是Commit T信息,则会将事务进行提交,并写入记录。
通常状况下,两阶段提交机制都能较好的运行,当在事务进行过程当中,有参与者宕机时,他重启之后,能够经过询问其余参与者或者协调者,从而知道这个事务到底提交了没有。固然,这一切的前提都是各个参与者在进行每一步操做时,都会事先写入日志。
惟一一个两阶段提交不能解决的困境是:当协调者在发出commit T消息后宕机了,而惟一收到这条命令的一个参与者也宕机了,这个时候这个事务就处于一个未知的状态,没有人知道这个事务究竟是提交了仍是未提交,从而须要 数据库管理员的介入,防止数据库进入一个不一致的状态。固然,若是有一个前提是:全部节点或者网络的异常最终都会恢复,那么这个问题就不存在了,协调者和 参与者最终会重启,其余节点也最终也会收到commit T的信息。
数据库日志保证了事务执行的原子性和持久性,日志类型能够分为redo log,undo log,undo/redo log。关于这几种日志形式的具体介绍,能够参照:http://nosql-wiki.org/foswiki/bin/view/Main/TransactonLog