1.什么是XA?XA协议本来就是一个分布式事务协议,它规定了XAPREPARE、XACOMMIT、XAROLLBACK等命令。XA协议规定了事务管理器(协调器)和资源管理器(数据节点)如何交互,共同完成分布式2PC的过程。XA主要规定了RM和TM之间的交互。我们来看看XA规范中定义的定义RM和TM之间的接口:xa_start负责开启或恢复一个事务分支,管理XID给调用线程xa_end负责取消当前线程与当前线程的关联事务分支xa_prepare负责询问RM是否准备提交事务分支xa_commit通知RM提交事务分支xa_rollback通知RM回滚事务分支XA协议使用两阶段协议,其中:第一阶段TM需要所有RM准备提交相应的事务分支,并询问RM是否有能力保证事务分支成功提交,RM根据自身情况,判断自己所做的工作是否可以提交,然后坚持工作内容,给TM一个OK的回执;否则,给TM一张NO的收据。RM发送否定回复并回滚已经完成的工作后,可以丢弃事务分支信息。第二阶段,TM根据第一阶段各RM准备的结果,决定是提交还是回滚事务。如果所有RM准备成功,则TM通知所有RM提交;如果没有RMpreparereceipt,TM通知所有RM回滚自己的事务分支。即TM和RM通过两阶段提交协议进行交互。二、MySQL中的XA实现1、内部XA事务在MySQL中,只有InnoDB引擎支持XA协议。内部XA事务主要用于协调存储引擎和二进制日志确认mysql是否启动了xa功能:测试手动执行xa事务:先使用XASTART'xid'启动一个XA事务并放入在ACTIVE状态下对于处于ACTIVE状态的XA事务,我们可以执行多个构成该事务的SQL语句,即指定分支事务的边界,然后执行一个XAEND'xid'语句,XAENDputs事务进入IDLE状态,即结束事务边界,xastart和xaend之间的语句构成分支事务的一个事务范围。调用xaend'xid1'后,事务边界结束,所以如果此时执行sql语句,ERROR1399(XAE07):XAER_RMFAIL:ThecommandcannotbeexecutedwhenglobaltransactionisintheIDLEstate错误,即当分支事务处于IDLE状态时,不允许执行其他不在分支事务边界内的sql。对于IDLE状态的XA事务,您可以执行XAPREPARE语句或XACOMMIT...ONEPHASE语句,其中XAPREPARE将事务置于PREPARED状态。此时的XARECOVER语句将在其输出中包含事务的xid值,因为XARECOVER列出了所有处于PREPARED状态的XA事务。XACOMMIT...ONEPHASE用于准备和提交事务,即转换为单阶段协议,直接提交事务。对于处于PREPARED状态的XA事务,可以执行XACOMMIT语句提交或者执行XAROLLBACK回滚xa事务。两阶段协议的第一阶段是执行xaprepare时。此时,MySQL客户端(TM)向MySQL数据库服务器(RM)发送准备“准备提交”请求,数据库收到请求后进行数据修改和日志记录。处理完成后,只需将事务的状态更改为“可以提交”,然后将结果返回给事务管理器即可。如果第一阶段数据库准备成功,则mysql客户端(TM)向数据库服务器发送“commit”请求,数据库服务器将事务的“committable”状态更改为“commitcompleted”状态,然后返回一个回应。如果第一阶段对数据库的操作出现错误,或者mysql客户端(RM)没有收到数据库的响应,则认为事务失败,执行回滚,撤回所有数据库事务。两阶段提交PCmysql的两阶段提交原理(1)perparephase1写入redolog,设置undostate=TRX_UNDO_PREPARED;2、刷新事务更新产生的重做日志;(2)commitphase1写binlog日志,生成事务2。设置undopage的状态为TRX_UNDO_TO_FREE或TRX_UNDO_TO_PURGE;//标记可以清除回滚段3.记录事务对应的binlog偏移量,写入系统表空间。两阶段提交是一种常用的跨系统维护数据逻辑一致性的方案。两个阶段都存在阻塞问题,建议三阶段提交在两个阶段的基础上增加一个pre-commit。(3)假设验证分为两个阶段:A.先写redolog,再写binlog。假设当redolog写完,binlog还没有写完,MySQL进程异常重启。前面说过,redolog写入后,即使系统crash了,数据还是可以恢复的,所以recovery后这一行c的值为1。但是因为binlog还没写完就crash了,所以这个statement此时并没有记录在binlog中。所以后面备份日志的时候,保存的binlog中是不存在这条语句的。然后你会发现如果需要用这个binlog来恢复临时库,因为这条语句的binlog丢失了,所以这次临时库更新的比较少,恢复的行中c的值为0,这不同于原库的价值不同。B、先写binlog,再写redolog。如果crash发生在binlog写入后,由于redolog还没有写入,crashrecovery后事务无效,所以这一行c的值为0。但是log》把c从0变成了1"已经记录在binlog中。所以后面用binlog恢复的时候,又会出现一个事务,恢复的行中c的值为1,和原来数据库的值不一样。(4)redo和binlog日志有以下三个区别。1、重做日志是InnoDB引擎独有的;binlog由MySQL的server层实现,所有引擎都可以使用。2、redolog是物理日志,记录“某个数据页发生了哪些变化”;binlog是逻辑日志,记录了这条语句的原始逻辑,比如“add1”。3、redolog是循环写入的,空间会一直用完;binlog可以另外写入。“追加写入”是指binlog文件写入到一定大小后,会切换到下一个,不会覆盖之前的日志。2、外部XA事务参与外部分布式事务(如多个数据库实现的分布式事务)。目前mysql对外部事务的支持还不够,这里就不过多描述了。总结以上就是本次对mysqlXA的理解和总结。我主要参考了mysql官方文档,加上自己的实践和理解。贴出mysql官方文档的地址。希望大家多多支持和关注。
