MySql 外部XA 事务

外部XA 事务

https://dev.mysql.com/doc/refman/8.0/en/xa.html

在MySQL中有两种XA事务。一方面,MySQL可以参与到外部的分布式事务中;另一方面,还可以通过XA事务来协调存储引擎和二进制日志。MySQL根据单机还是分布式集群分为内部XA和外部XA。

对于内部XA,MySQL Server中的存储引擎充当资源管理器,而Server层本身充当事务管理器(binlog充当协调者的角色),也就是一个事务涉及到同一MySQL服务器中的两个innodb数据库(因为其它引擎不支持XA)的跨库XA事务。

1. 背景介绍

InnoDB存储引擎支持XA事务。MySQL XA实现基于X/Open CAE文档分布式事务处理:XA规范.

在客户端,没有特殊的要求。到MySQL服务器的XA接口由以XA关键字开头的SQL语句组成。MySQL客户端程序必须能够发送SQL语句并理解XA语句接口的语义。它们不需要链接到最近的客户端库。旧的客户端库也可以使用

XA支持分布式事务,即允许多个独立事务资源参与全局事务的能力。

全局事务涉及几个本身具有事务性的操作,但是所有操作必须作为一个组成功完成,或者全部作为一个组回滚。从本质上讲,这将ACID属性“向上扩展了一个级别”,以便多个ACID事务可以作为同样具有ACID属性的全局操作的组件一起执行。

分布式事务的一些例子:

  • 应用程序可以作为集成工具,将消息传递服务与RDBMS结合起来。应用程序确保处理消息发送、检索和处理(也涉及事务数据库)的事务都发生在全局事务中。你可以把它想象成“事务性电子邮件”。

  • 应用程序执行涉及不同数据库服务器的操作,例如MySQL服务器和Oracle服务器(或多个MySQL服务器),其中涉及多个服务器的操作必须作为全局事务的一部分发生,而不是作为每个服务器本地的单独事务。

  • 银行将账户信息保存在RDBMS中,并通过自动柜员机(atm)分发和接收资金。有必要确保ATM操作正确地反映在帐户中,但这不能单独使用RDBMS完成。全局事务管理器集成了ATM和数据库资源,以确保金融事务的整体一致性。

    假设一个用户在ATM机进行银行的转账操作,例如持卡人从招商银行的储蓄卡转账10000元到工商银行的储蓄卡。在这种情况下,可以将ATM机视为节点A,招商银行的后台数据库视为节点B,工商银行的后台数据库视为节点C,这个转账的操作可以分解为以下的步骤:

    1,节点A发出转账命令;
    2,节点B执行储蓄卡中的余额值减去10000;
    3,节点C执行储蓄卡中的余额值加上10000;
    4,节点A通知用户操作完成或者节点A通过用户操作失败。

    这里需要使用分布式事务,因为节点A 不能通过调用 一台 数据库就完成操作。
    其需要访问网络中两个节点的数据库,而在每个节点的数据库执行的事务操作又都是扁平的。
    对于分布式事务,其同样需要满足ACID特性,要么都发送,要么都失效。

使用全局事务的应用程序涉及一个或多个资源管理器和一个事务管理器:

1,资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
资源管理器(Resource Manager, RM)提供对事务资源的访问。数据库服务器是一种资源管理器。必须能够提交或回滚RM管理的事务。

2,事务管理器:协调参与全局事务中的各个事务。需要和参与全局事务的所有资源管理器进行通信。
事务管理器™协调作为全局事务一部分的事务。它与处理这些事务的rm进行通信。全局事务中的单个事务是全局事务的“分支”。全局事务及其分支由稍后描述的命名方案标识。

MySQL的XA实现使MySQL服务器能够充当资源管理器,在全局事务中处理XA事务。连接到MySQL服务器的客户端程序充当事务管理器。

为了保证分布式事务正确完成的一种算法是 two-phase commit (2PC) 两阶段提交。

分布式事务使用两段式提交(two-phase commit)的方式。执行全局事务的过程使用两阶段提交(2PC)。这将在执行全局事务分支执行的操作之后发生。

在第一阶段,所有参与全局事务的节点都开始准备(prepare),告诉事务管理器它们准备好提交了。

在第二阶段,事务管理器告诉资源管理器执行rollback还是commit。如果任何一个节点显示不能提交,则所有的节点都被告知需要回滚。

可见与本地事务不同的是,分布式事务需要多一次的prepare操作,待收到所有节点的同意信息后,再进行commit或是rollback操作。

在某些情况下,全局事务可能使用一阶段提交(1PC)。例如,当Transaction Manager发现全局事务仅由一个事务资源(即单个分支)组成时,可以通知该资源同时准备和提交。

2. XA Transaction SQL Statements

语法

XA {START|BEGIN} xid [JOIN|RESUME] //开启XA事务,如果使用的是XA START而不是XA BEGIN,那么[JOIN|RESUME]将不会生效,xid是一个唯一值,表示事务分支标识符

XA END xid [SUSPEND [FOR MIGRATE]] //结束一个XA事务,对于[SUSPEND [FOR MIGRATE]] 可以识别但不生效

XA PREPARE xid 准备提交

XA COMMIT xid [ONE PHASE] //提交,如果使用了ONE PHASE,则表示使用一阶段提交。两阶段提交协议中,如果只有一个RM参与,那么可以优化为一阶段提交。在某些情况下,全局事务可能使用单阶段提交 (1PC)。例如,当事务管理器发现全局事务仅包含一个事务资源(即单个分支)时,可以告知该资源同时准备和提交。

XA ROLLBACK xid //回滚

XA RECOVER [CONVERT XID]  //列出所有处于PREPARE阶段的XA事务

每个XA语句都以XA关键字开头,其中大多数语句都需要一个xid值。xid是XA事务标识符。它指示语句应用于哪个事务。xid由一到三部分组成

xid: gtrid [, bqual [, formatID ]]

grid是一个全局事务标识符
bqual是一个分支限定符
而formatID是一个数字,用于标识网格和bqual值所使用的格式。

如语法所示,bqual和formatID是可选的。默认的相等值是“如果没有给出”。如果没有给出,默认的formatID值是1。

Gtrid和bqual必须是字符串,每个字符长度不超过64字节(不是字符)。

Gtrid和bqual可以用几种方式指定。可以使用带引号的字符串(‘ab’)、十六进制字符串(X’6162’, 0x6162)或位值(b’nnnn’)。

formatID is an unsigned integer.

gtrid和bqual值由MySQL服务器底层的XA支持例程以字节为单位解释。但是,在解析包含XA语句的SQL语句时,服务器使用一些特定的字符集。为了安全起见,将grid和bqual写成十六进制字符串。

xid值通常由事务管理器生成。一个TM生成的值不能和其他TM生成的值相同。给定的TM必须能够在XA RECOVER语句返回的值列表中识别自己的xid值。

XA START xid使用给定的xid值启动XA事务。每个XA事务必须具有唯一的xid值,因此该值当前不能被另一个XA事务使用。唯一性使用gtrid和bqual值进行评估。对于XA事务,必须使用与XA START语句中给定的相同的xid值来指定接下来的所有XA语句。如果使用这些语句中的任何一条,但指定的xid值与某些现有XA事务不对应,就会发生错误。

从MySQL 8.0.31开始,当服务器使用–replication-do-db或–replication-ignore-db运行时,默认数据库不会过滤XA START、XA BEGIN、XA END、XA COMMIT和XA ROLLBACK语句。

replicate-ignore-db:在主从同步的环境中,replicate-ignore-db用来设置不需要同步的库。
Replicate_Do_DB:参数是在slave上配置,指定slave要复制哪个库

一个或多个XA事务可以同一个全局事务的一部分。给定全局事务中的所有XA事务必须在xid值中使用相同的gtrid值。因此,gtrid的值必须是全局唯一的,这样就不会对给定XA事务所属的全局事务产生不确定性。对于全局事务中的每个XA事务,xid值的bqual部分必须是不同的。(要求bqual的值不同是当前MySQL XA实现的一个限制。这不是XA规范的一部分)。

XA RECOVER语句返回MySQL服务器上处于准备状态的XA事务的信息。(参见第13.3.8.2节“XA事务状态”。)服务器上的每个XA事务的输出都包含一行,而不管哪个客户端启动了它。

XA RECOVER需要XA_RECOVER_ADMIN权限。这个特权需求阻止用户发现除自己的事务之外的未完成的准备好的XA事务的XID值。它不影响XA事务的正常提交或回滚,因为启动它的用户知道它的XID。

XA RECOVER输出行如下所示(例如xid值由’abc’、'def’和7组成):

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|        7 |            3 |            3 | abcdef |
+----------+--------------+--------------+--------+

输出列的含义如下:

formatID是事务id的formatID部分

Gtrid_length是xid的gtrid部分的长度(以字节为单位)

Bqual_length是xid的bqual部分的长度,以字节为单位

Data是xid的gtrid和bqual部分的连接

XID值可能包含不可打印字符。XA RECOVER允许一个可选的CONVERT XID子句,这样客户端可以请求十六进制的XID值。

3. XA Transaction States

XA事务的状态,按照如下步骤进行展开

1.使用XA START来启动一个XA事务,并把它置于ACTIVE状态。

2.对于一个ACTIVE状态的 XA事务,我们可以执行构成事务的SQL语句,然后发布一个XA END语句。XA END把事务放入IDLE状态。

3.对于一个IDLE 状态XA事务,可以执行一个XA PREPARE语句或一个XA COMMIT…ONE PHASE语句:

XA PREPARE把事务放入PREPARED状态。在此点上的XA RECOVER语句将在其输出中包括事务的xid值,因为XA RECOVER会列出处于PREPARED状态的所有XA事务。

XA COMMIT…ONE PHASE用于预备和提交事务。xid值将不会被XA RECOVER列出,因为事务终止。

4.对于一个PREPARED状态的 XA事务,您可以发布一个XA COMMIT语句来提交和终止事务,或者发布XA ROLLBACK来回滚并终止事务。

下面是一个简单的XA事务,它将一行作为全局事务的一部分插入到表中:

mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)

mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)

在MySQL 8.0.28及更早的版本中,在给定客户端连接的上下文中,XA事务和本地(非XA)事务是互斥的。例如,如果已经发出XA START来开始XA事务,则只有在提交或回滚XA事务之后才能启动本地事务。相反,如果使用START transaction启动本地事务,则在提交或回滚事务之前,不能使用XA语句。

MySQL 8.0.29及更高版本支持分离的XA事务,由xa_detach_on_prepare系统变量启用(默认开启)。在执行XA PREPARE之后,分离的事务将与当前会话断开连接(并且可以由另一个连接提交或回滚)。这意味着当前会话可以自由地启动一个新的本地事务或XA事务,而不必等待准备好的XA事务提交或回滚。

当XA事务被分离时,连接对它准备的任何XA事务都没有特殊的知识。如果当前会话在另一个连接已经提交或回滚给定的XA事务(甚至是它准备的事务)之后试图提交或回滚,则会以无效的XID错误(ER_XAER_NOTA)拒绝该尝试,因为请求的XID不再存在。

请注意: 分离的xa事务不支持临时表

当分离的XA事务被禁用时(xa_detach_on_prepare设置为OFF), XA事务将保持连接,直到原始连接提交或回滚它为止,如前面为MySQL 8.0.28和更早版本所述。对于在组复制中使用的MySQL服务器实例,不建议禁用分离的XA事务;

分离的XA事务。

MySQL 8.0.29及以后版本支持独立XA事务。分离事务是指一旦准备好,就不再连接到当前会话的事务。这是执行XA PREPARE时自动发生的。准备好的XA事务可以由另一个连接提交或回滚,然后当前会话可以启动另一个XA事务或本地事务,而无需等待刚刚准备完成的事务。

当启用分离的XA事务支持(xa_detach_on_prepare = ON)时,到该服务器的任何连接都可以列出(使用XA RECOVER)、回滚或提交任何准备好的XA事务。此外,不能在分离的XA事务中使用临时表。

可以通过将xa_detach_on_prepare设置为OFF来禁用对分离XA事务的支持,但不建议这样做。特别是,如果该服务器被设置为MySQL组复制中的实例,则应该将该变量设置为默认值(ON)。

如果XA事务处于ACTIVE状态,则不能发出任何导致隐式提交的语句。这将违反XA合约,因为您无法回滚XA事务。尝试执行这样的语句会引发以下错误:

ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed
when global transaction is in the ACTIVE state

导致隐式提交的语句有:

  1. 定义或修改数据库对象的数据定义语言(DDL)语句。
    ALTER EVENT, ALTER FUNCTION, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER TABLESPACE, ALTER VIEW, CREATE DATABASE, CREATE EVENT, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE ROLE, CREATE SERVER, CREATE SPATIAL REFERENCE SYSTEM, CREATE TABLE, CREATE TABLESPACE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP EVENT, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP ROLE, DROP SERVER, DROP SPATIAL REFERENCE SYSTEM, DROP TABLE, DROP TABLESPACE, DROP TRIGGER, DROP VIEW, INSTALL PLUGIN, RENAME TABLE, TRUNCATE TABLE, UNINSTALL PLUGIN.

    如果使用了TEMPORARY关键字,CREATE TABLE和DROP TABLE语句不会提交事务。(这不适用于对临时表的其他操作,如ALTER TABLE和CREATE INDEX,这些操作会导致提交。)然而,尽管没有发生隐式提交,但也不能回滚语句,这意味着使用此类语句会导致事务原子性被破坏。例如,如果使用CREATE TEMPORARY TABLE,然后回滚事务,则表仍然存在。

  2. 隐式使用或修改mysql数据库中的表的语句。

    ALTER USER, CREATE USER, DROP USER, GRANT, RENAME USER, REVOKE, SET PASSWORD.

  3. 事务控制和锁定语句。

    BEGIN, LOCK TABLES, SET autocommit = 1(如果值不是1),START TRANSACTION, UNLOCK TABLES。

    只有当当前有表被LOCK TABLES锁以获取非事务性表锁时,UNLOCK TABLES才会提交事务。在FLUSH TABLES WITH READ LOCK之后的UNLOCK TABLES不会发生提交,因为后者语句不会获取表级锁。

    事务不能嵌套。这是在发出START transaction语句或其同义词之一时对任何当前事务执行隐式提交的结果。

    当XA事务处于ACTIVE状态时,不能在事务中使用导致隐式提交的语句。

  4. Data loading statements. LOAD DATA. LOAD DATA

  5. Administrative statements. ANALYZE TABLE, CACHE INDEX, CHECK TABLE, FLUSH, LOAD INDEX INTO CACHE, OPTIMIZE TABLE, REPAIR TABLE, RESET (but not RESET PERSIST).

  6. Replication control statements. START REPLICA, STOP REPLICA, RESET REPLICA, CHANGE REPLICATION SOURCE TO, CHANGE MASTER TO.

4. Restrictions on XA Transactions

XA事务支持仅限于InnoDB存储引擎。

对于“外部XA”,MySQL服务器充当资源管理器,客户端程序充当事务管理器。
对于“内部XA”,MySQL服务器中的存储引擎充当rm,服务器本身充当TM。
内部XA支持受限于单个存储引擎的功能。
处理涉及多个存储引擎的XA事务需要内部XA。内部XA的实现要求存储引擎支持表处理程序级别的两阶段提交,目前只有InnoDB支持。

对于全局事务中的每个XA事务,xid值的相等部分是不同的这一要求是当前MySQL XA实现的一个限制。它不是XA规范的一部分。

XA事务分两部分写入二进制日志。当发出XA PREPARE时,使用初始GTID编写XA PREPARE之前的事务的第一部分。XA_prepare_log_event用于在二进制日志中标识此类事务。当发出XA COMMIT或XA ROLLBACK时,使用第二个GTID编写仅包含XA COMMIT或XA ROLLBACK语句的事务的第二部分。

注意,事务的初始部分(由XA_prepare_log_event标识)不一定后跟它的XA COMMIT或XA ROLLBACK,这可能导致任意两个XA事务的二进制日志记录交错。XA事务的两个部分甚至可以出现在不同的二进制日志文件中。这意味着,在发出显式的XA COMMIT或XA ROLLBACK语句之前,处于PREPARED状态的XA事务现在是持久的,从而确保XA事务与复制兼容。

在复制中,在XA事务准备好之后,它立即从复制应用程序线程中分离出来,并且可以由副本上的任何线程提交或回滚。这意味着同一个XA事务可以以不同线程上的不同状态出现在events_transactions_current表中。

events_transactions_current表显示线程上最近监视的事务事件的当前状态,并且在线程空闲时不更新此状态。因此,在XA事务被另一个线程处理之后,它仍然可以显示为原始应用程序线程的PREPARED状态。要确定仍处于PREPARED状态并需要恢复的XA事务,请使用XA RECOVER语句而不是Performance Schema事务表。

使用XA事务存在以下限制:

  1. 在MySQL 8.0.30之前,相对于二进制日志,XA事务不能完全适应意外停止。如果服务器在执行XA PREPARE、XA COMMIT、XA ROLLBACK或XA COMMIT时出现意外中断……ONE PHASE statement,服务器可能无法恢复到正确的状态,使服务器和二进制日志处于不一致的状态。在这种情况下,二进制日志可能包含未应用的额外XA事务,或者错过已应用的XA事务。此外,如果启用了gtid,则在恢复后@@GLOBAL。gtid_performed可能无法正确描述已应用的事务。注意,如果在XA PREPARE之前、XA PREPARE和XA COMMIT(或XA ROLLBACK)之间、或XA COMMIT(或XA ROLLBACK)之后发生意外中断,则服务器和二进制日志将被正确恢复并恢复到一致状态。

从MySQL 8.0.30开始,这不再是一个问题;服务器将XA PREPARE实现为两阶段操 作,它维护存储引擎和服务器之间的PREPARE操作的状态,并在存储引擎和二进制日志之间强加执行顺序,以便状态在服务器节点上保持一致和持久之前不会广播。

您应该意识到,当使用相同的事务XID顺序执行XA事务,并且在处理XA COMMIT期间发生中断时……在ONE PHASE,可能不再可能同步二进制日志和存储引擎之间的状态。如果刚才描述的一系列事件发生在存储引擎中准备好这个事务之后,而XA COMMIT语句仍在执行,则会发生这种情况。这是一个已知的问题。

  1. 不支持将复制过滤器或二进制日志过滤器与XA事务结合使用。对表进行过滤可能会导致副本上的XA事务为空,并且不支持空XA事务。此外,由于副本的连接元数据存储库和应用程序元数据存储库存储在InnoDB表中,这在MySQL 8.0中成为默认值,数据引擎事务的内部状态在经过过滤的XA事务之后被更改,并且可能与复制事务上下文状态不一致。

每当XA事务受到复制过滤器的影响时,无论事务是否为空,都会记录错误ER_XA_REPLICATION_FILTERS。如果事务不为空,则副本能够继续运行,但是您应该采取措施停止对XA事务使用复制过滤器,以避免潜在的问题。如果事务为空,则副本停止。在这种情况下,副本可能处于未确定状态,在这种状态下复制进程的一致性可能会受到损害。特别是,副本的副本上的gtid_executed set可能与源上的不一致。要解决这种情况,隔离源并停止所有复制,然后检查跨复制拓扑的GTID一致性。撤销生成错误消息的XA事务,然后重新启动复制。

  1. 对于基于语句的复制,XA事务被认为是不安全的。如果在源上并行提交的两个XA事务以相反的顺序在副本上准备,则可能发生无法安全解决的锁定依赖,并且复制可能会因副本上的死锁而失败。这种情况可能发生在单线程或多线程副本中。当设置binlog_format=STATEMENT时,会对XA事务中的DML语句发出警告。当设置了binlog_format=MIXED或binlog_format=ROW时,使用基于行的复制记录XA事务中的DML语句,并且不存在潜在的问题。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值