什么是MySQL XA ?
MySQL XA 是基于Open Group 的<
什么是DTP?
分布式事务处理(Distributed Transaction Processing),简称DTP。
什么是DTP模型?
一个DTP模型实例,至少有3个组成部分:AP、RM、TM
AP:应用程序(Application Program),用于定义事务边界,即定义事务的开始和结束,并且在事务边界内对资源进行操作。
RM:资源管理器(Resource Manager),事务的参与者,通常是数据库,比如MySQL Server。一个分布式事务通常涉及多个资源管理器。
TM:事务管理器(Transaction Manager),创建分布式事务并协调分布式事务中的各个子事务的执行和状态。子事务是指分布式事务中在RM上执行的具体操作。
分布式事务场景下,需要跨多个应用,操作多个数据库,每一个数据库可以看成一个RM;在DTP模型中,可以看成一个AP需要操作多个RM上的资源,AP通过TM来声明一个全局事务,然后操作不同的RM上的资源,最后通知TM来提交或者回滚全局事务。
什么二阶段提交协议(2PC)?
从字面的意思理解,Two Phase Commit,就是将提交commit过程划分为2个阶段phase。是为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法。二阶段提交的思路可以概括为: 参与者(RM)将操作成败通知协调者(TM),再由协调者(TM)根据所有参与者(RM)的反馈情报决定各参与者(RM)是否要提交操作还是中止操作。
第一阶段:TM通知各个RM准备提交它们的事务分支。如果RM判断自己进行的工作可以被提交,那就对工作内容进行持久化,再给TM肯定答复;要是发生了其他情况,那给TM的都是否定答复。在发送了否定答复并回滚了已经的工作后,RM就可以丢弃这个事务分支信息。
以mysql数据库为例,在第一阶段,事务管理器向所有涉及到的数据库服务器发出prepare"准备提交"请求,数据库收到请求后执行数据修改和日志记录等处理,处理完成后只是把事务的状态改成"可以提交",然后把结果返回给事务管理器。
第二阶段:TM根据阶段1各个RM prepare的结果,决定是提交还是回滚事务。如果所有的RM都prepare成功,那么TM通知所有的RM进行提交;如果有RM prepare失败的话,则TM通知所有RM回滚自己的事务分支。
以mysql数据库为例,如果第一阶段中所有数据库都prepare成功,那么事务管理器向数据库服务器发出"确认提交"请求,数据库服务器把事务的"可以提交"状态改为"提交完成"状态,然后返回应答。如果在第一阶段内有任何一个数据库的操作发生了错误,或者事务管理器收不到某个数据库的回应,则认为事务失败,回撤所有数据库的事务。数据库服务器收不到第二阶段的确认提交请求,也会把"可以提交"的事务回撤。
MySql对XA事务的支持
Among the MySQL Connectors, MySQL Connector/J 5.0.0 and higher supports XA directly, by means of a class interface that handles the XA SQL statement interface for you.
MySQL Connector/J 从5.0.0版本之后开始直接提供对XA的支持。 MySQL 从5.0.3开始支持XA分布式事务,且只有InnoDB存储引擎支持。
MySql XA事务语法
XA {START|BEGIN} xid [JOIN|RESUME]:开启一个事务,并将事务置于ACTIVE状态,此后执行的SQL语句都将置于该是事务中。xid是一个唯一值,表示事务分支标识符。
XA END xid [SUSPEND [FOR MIGRATE]]:结束一个事务。
XA PREPARE xid:实现事务提交的准备工作,事务状态置于PREPARED状态。事务如果无法完成提交前的准备操作,该语句会执行失败。
XA COMMIT xid [ONE PHASE]:事务最终提交,完成持久化。
XA ROLLBACK xid:事务回滚。
XA RECOVER [CONVERT XID]:列出所有处于PREPARE阶段的XA事务。
MySql XA事务状态
An XA transaction progresses through the following states:
XA事务的状态,按照如下步骤进行展开
1、Use XA START to start an XA transaction and put it in the ACTIVE state.
使用XA START来启动一个XA事务,并把它置于ACTIVE状态。
2、For an ACTIVE XA transaction, issue the SQL statements that make up the transaction, and then issue an XA END statement. XA END puts the transaction in the IDLE state.
对于一个ACTIVE状态的 XA事务,我们可以执行构成事务的SQL语句,然后发布一个XA END语句。XA END把事务放入IDLE状态。
3、For an IDLE XA transaction, you can issue either an XA PREPARE statement or an XA COMMIT ... ONE PHASE statement:
对于一个IDLE 状态XA事务,可以执行一个XA PREPARE语句或一个XA COMMIT…ONE PHASE语句:
·XA PREPARE puts the transaction in the PREPARED state. An XA RECOVER statement at this point will include the transaction's xid value in its output, because XA RECOVER lists all XA transactions that are in the PREPARED state.
XA PREPARE把事务放入PREPARED状态。在此点上的XA RECOVER语句将在其输出中包括事务的xid值,因为XA RECOVER会列出处于PREPARED状态的所有XA事务。
·XA COMMIT ... ONE PHASE prepares and commits the transaction. The xid value will not be listed by XA RECOVER because the transaction terminates.
XA COMMIT…ONE PHASE用于预备和提交事务。xid值将不会被XA RECOVER列出,因为事务终止。
4、For a PREPARED XA transaction, you can issue an XA COMMIT statement to commit and terminate the transaction, or XA ROLLBACK to roll back and terminate the transaction.
对于一个PREPARED状态的 XA事务,您可以发布一个XA COMMIT语句来提交和终止事务,或者发布XA ROLLBACK来回滚并终止事务。
5、Within the context of a given client connection, XA transactions and local (non-XA) transactions are mutually exclusive. For example, if XA START has been issued to begin an XA transaction, a local transaction cannot be started until the XA transaction has been committed or rolled back. Conversely, if a local transaction has been started with START TRANSACTION, no XA statements can be used until the transaction has been committed or rolled back.
针对一个给定的客户端连接而言,XA事务和非XA事务(即本地事务)是互斥的。例如,已经执行了”XA START”命令来开启一个XA事务,则本地事务不会被启动,直到XA事务已经被提交或被 回滚为止。相反的,如果已经使用START TRANSACTION启动一个本地事务,则XA语句不能被使用,直到该事务被提交或被 回滚为止。
6、If an XA transaction is in the ACTIVE state, you cannot issue any statements that cause an implicit commit. That would violate the XA contract because you could not roll back the XA transaction. You will receive the following error if you try to execute such a statement:
最后,如果一个XA事务处于ACTIVE状态,是不能直接进行提交的,如果这样做,mysql会抛出异常:
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed
when global transaction is in the ACTIVE state
MySql XA如何实现分布式事务的ACID
1. 当xa start开启事务后,DML也会在对应的RM上创建undo以及read view(该read view是instance级别的)。
2. 当xa prepare 时会将子事务置于PREPARED状态,此时子事务已经完成事务提交前的所有准备工作(获得锁,并将PREPARED状态记录到共享表空间中,会将xa start到xa end之间操作记录在binlog中)。
3. 当xa commit 时会在binlog中记录xa commit xid, 并将innodb中PREPARED状态转化为COMMITED状态。
4. 当xa commit one phase 时会同时进行prepare和commit 两种操作,是在TM发现全局的分布式事务只涉及一个RM时进行的(因为不需要等待其他RM的反馈结果)。
5. 当xa rollback在xa prepare前时,因为没有写binlog和redo,只会释放undo, read view以及lock。
6. 当xa rollback 在xa prepare之后时,除了需要释放undo, read view以及lock,还需要binlog中记录xa rollback xid(使得从库不会提交该事务)以及innodb中将PREPARED状态转化为ROLLBACK状态。
java操作MySql XA事务
1、接口实例化
2、每一个分支sql操作,以及二阶段提交处理
MySQL Connector XA事务支持源码简单分析
1、调用的是MySqlXaConnection,一般获取一个普通的DriverManager.getConnection()之后,封装成了MySqlXaConnection。
2、调用XAResource的start方法来开启XA事务;在调用start方法时,实际上就是执行了一个“XA START xid[JOIN|RESUME]”命令而已,和上面讲解XA命令的第一步操作实际上一样,只不过java封装简化了我们的操作。
3、end操作,结束一个事务。和start()方法一样,同样传入一个xid和一个flag标记,最后dispatchCommand()方法执行命令操作。
4、prepare操作,执行的是一个XA PREPARE命令。
5、commit操作;如果是onePhase为true,会加入 ONE PHASE命令,不需要等待其他RM反馈prepare的结果。
6、rollback操作。
7、recover操作,查看当前处于prepare状态的xa事务,收集到的各MySQL数据库实例返回的xid列表,然后再对比应用程序端日志,决定这些xid,哪些全局commit,哪些rollback。
MySql XA 5.7.7改进之处
在5.7.7之前,如果客户端连接已终止或服务器正常退出,则回滚PREPARED事务。当客户端被Kill时,所有事务都被回滚。因此,即使XA事务处于PREPARED状态,它也无法在XA RECOVER期间恢复事务。之所以MySQL这么实现是因为MySQL 5.7.7 之前PREPARED的事务并不会记录到binlog中。客户端退出后会丢失该信息,如果允许再提交,那么binlog缺少事务信息,会造成主从不一致。
在MySQL 5.7.7 之后,克服上述限制需要更改XA事务恢复机制和二进制日志记录机制,MySQL 新增了一个XA_prepare_log_event的事件,会把xa start到xa prepare中间的操作记录到Binlog中。Slave读取Relay log 进行回放,当SQL Thread读取到PREPARED的事务后,在读取xa commit或者xa rollback前,会进行一个类似客户端断开的操作,继续读取后续的事务信息,不会阻塞SQL Thread的执行。