暂无图片
暂无图片
2
暂无图片
暂无图片
1
暂无图片

分布式 MySQL XA 详解。

原创 aisql 2022-05-10
4469

MySQL XA可应用于两种场景
1、同一实例下的不同引擎。
2、不同实例下的数据库。

现在几乎都是用 InnoDB、所以此文主要讲第二种场景。不同实例下的数据库实现分布式事务。

一、MySQL XA语句

1、XA START ‘xid’

开启全局事务,将状态置为active
xid 全局唯一

2、XA END ‘xid’

将事务状态置为IDLE
确定DML语句结束
START/END 也标明参与全局事务的语句边界

3、XA PREPARE ‘xid’

将事务状态置为PREPARED
对于成功的事务,可以通过 XA RECOVER 查询。

4、XA COMMIT ‘xid’

将事务提交

5、XA ROLLBACK ‘xid’

将事务回滚

二、MySQL XA 三个重要的节点

1、AP 应用程序
2、TM 事务管理器 --事务协调整者,根据RM反馈的状态,决定提交,回滚等操作。
3、RM 资源管理器 --通常就是指MySQL 库本身

AP、TM、RM 图

MySQL XA.jpg

三、程序实例

下面我用C#写了一段控制台充当TM

C#控制台实例

using System; using MySql.Data.MySqlClient; namespace TestMysqlXA { internal class Program { static string connstr1 = "server=192.168.1.1;port=3521;user=dev;database=DEV;password=1232"; static string connstr2 = "server=192.168.1.2;port=3306;user=test;database=test;password=123"; static void Main(string[] args) { using (MySqlConnection conn1 = new MySqlConnection(connstr1)) using (MySqlCommand com1 = conn1.CreateCommand()) using (MySqlConnection conn2 = new MySqlConnection(connstr2)) using (MySqlCommand com2 = conn2.CreateCommand()) { conn1.Open(); conn2.Open(); string sql = "XA START '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com1.CommandText = sql; com2.CommandText = sql; com1.ExecuteNonQuery(); com2.ExecuteNonQuery(); try { com1.CommandText = "insert into multi_dbtrans values(3, '商品3');"; com1.ExecuteNonQuery(); com1.CommandText = "XA END '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com1.ExecuteNonQuery(); com2.CommandText = "update multi_dbtrans set goodsname = '111' where goodsid = 1 ;"; com2.ExecuteNonQuery(); com2.CommandText = "insert into multi_dbtrans values(3, '商品3');"; com2.ExecuteNonQuery(); com2.CommandText = "XA END '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com2.ExecuteNonQuery(); com1.CommandText = "XA PREPARE '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com1.ExecuteNonQuery(); com2.CommandText = "XA PREPARE '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com2.ExecuteNonQuery(); sql = "XA COMMIT '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com1.CommandText = sql; com2.CommandText = sql; com1.ExecuteNonQuery(); com2.ExecuteNonQuery(); } catch (Exception ex) { sql = "XA ROLLBACK '3f68419a-cde3-11ec-a6e1-0c42a1b776e7'"; com1.CommandText = sql; com2.CommandText = sql; com1.ExecuteNonQuery(); com2.ExecuteNonQuery(); } Console.ReadLine(); } } } }
复制

四、异常处理

1、构建测试数据

create table if not exists multi_dbtrans ( goodsid int not null comment '主键ID', goodsname varchar(50) not null comment '商品名称', primary key pk_goodsid(goodsid) )engine = innodb comment '测试表';
复制

插入测试数据

insert into multi_dbtrans values(1,'商品1'),(3,'商品3');
复制

2、在DML语句处有RM出现异常

xa start '111222'; update multi_dbtrans set goodsname = '111' where goodsid = 1 ; insert into multi_dbtrans -- 此语句会报错,因为已有goodsid = 3 的了。 values(3,'商品3');
复制

image.png

这时可以看到已有锁了。
image.png

所以如第二图所示,在DML语句时,就已加锁了。

但对于没有 XA PREPARE 的事务
用XA RECOVER; 是查询不到的
image.png

那该怎么查询呢。
可通过下列语句查询

SELECT parent.xid_gtrid,child.* FROM performance_schema.events_transactions_current AS parent INNER JOIN performance_schema.data_locks AS child WHERE parent.THREAD_ID = child.THREAD_ID AND parent.EVENT_ID < child.EVENT_ID AND ( child.EVENT_ID <= parent.END_EVENT_ID OR parent.END_EVENT_ID IS NULL );
复制

image.png
通过上面语句,可以看到这个xid.

但是对于 没有 XA END 的事务来说,是不能rollback或commit的
image.png

那怎么才能释放资源呢。
有两种方法。
第一种。断开连接
只要连接断开。该事务就自动回滚了。所有资源就释放掉了

第二种。 kill掉
通过data_locks 可以看到 THREAD_ID

select * from performance_schema.data_locks;
复制

image.png

再通过threads表找到PROCESSLIST_ID

select * from performance_schema.threads WHERE THREAD_ID = 94
复制

image.png

还可以通过 events_transactions_current 确定xid是不是一致的。

select * from performance_schema.events_transactions_current where thread_id = 141
复制

image.png

通过 events_statements_history 表可以找到 该事务包含的语句。

SELECT * FROM performance_schema.events_statements_history WHERE thread_id=141
复制

image.png

找到PROCESSLIST_ID
然后就可以kill了

kill 50
复制

Kill 后 锁资源等都释放了。

2、在XA PREPARE语句处有RM出现异常

对于未成功XA PREPARE 的事务,可以采用三种方式释放事务
1、连接断开自动回滚
2、kill pid 回滚
3、手动 XA ROLLBACK 回滚。

对于成功XA PREPARE 的事务
只能通过 XA ROLLBACK 回滚。或 XA COMMIT提交

对于已成功XA PREPARE 的事务。连接断开,服务重启都不会自动回滚或提交。必须手动处理

已成功 XA PREPARE 的事务可通过 XA RECOVER 直接查看。

XA RECOVER;
复制

image.png

此时可以手动执行 XA ROLLBACK ‘111222’ 或 XA COMMIT ‘111222’

2、在XA COMMIT语句处有RM出现异常

对于已成功 XA COMMIT 的事务,数据库RM已完成了持久化,不能回滚。如果需要回滚需要TM反向操作自己实现回滚。

对于未成功XA COMMIT 的事务 参见上点。处理方式。

好的。MySQL XA整体的介始就到此了。

最后做一个总结吧

总结

1、MySQL XA 并不是强一致性的分布式事务。因为最后一步,有可能有些RM已Commit 而有的RM 由于网络等原因未收到Commit命令。
这就需要TM 根据业务需要来决定是 COMMIT还是ROLLBACK. 达到最终一致性。
2、事务锁资源时间较长,对性能有影响,当第一个RM 执行DML的时候,第一个RM就已上锁完成。 需要等到所有RM提交才释放锁。所以对于第一个RM锁的时候更长,实际中当然可以参照2PL 特性,将资源争抢最历害的RM放在最后。
3、没有全局的ReadView,因为MySQL的ReadView 是实例级别的。 .对一致性读要求较高的业务,肯定不适合MySQL XA。要么就需要TM来实现全局的ReadView.

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

墨天轮福利君
暂无图片
2年前
评论
暂无图片 0
您好,您的文章已入选墨力原创作者计划合格奖,10墨值奖励已经到账请查收! ❤️我们还会实时派发您的流量收益。
2年前
暂无图片 点赞
评论
chengang
暂无图片
关注
暂无图片
获得了897次点赞
暂无图片
内容获得231次评论
暂无图片
获得了297次收藏
TA的专栏
MySQL生产实战优化
收录15篇内容
有意思的SQL
收录13篇内容
MySQL事务
收录2篇内容
目录
  • 一、MySQL XA语句
    • 1、XA START ‘xid’
    • 2、XA END ‘xid’
    • 3、XA PREPARE ‘xid’
    • 4、XA COMMIT ‘xid’
    • 5、XA ROLLBACK ‘xid’
  • 二、MySQL XA 三个重要的节点
    • AP、TM、RM 图
  • 三、程序实例
    • C#控制台实例
  • 四、异常处理
    • 1、构建测试数据
    • 2、在DML语句处有RM出现异常
    • 2、在XA PREPARE语句处有RM出现异常
    • 2、在XA COMMIT语句处有RM出现异常
  • 总结