乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 数据库基础与安装

    • MySQL 简介
    • MySQL 5.6 到 5.7 到 8.0 关键差异速查
    • 安装 MySQL 5.7
    • 连接与断开服务器
    • 创建数据库
    • 创建数据表
    • 数据库与数据表
    • 加载数据
    • 获取数据库信息
    • 批处理模式
    • SHOW 语句汇总
    • FLUSH 与 RESET 语句
    • my.cnf 核心参数
    • 字符集与排序规则
  • 第2章 SQL基础查询

    • SELECT
    • WHERE
    • ORDER BY
    • LIMIT
    • COUNT
    • 聚合函数
    • 比较运算符
    • 逻辑运算符
    • 算术运算符
    • 模式匹配
    • NULL 值处理
    • UPDATE
    • DELETE
    • REPLACE
    • SELECT INTO
  • 第3章 数据类型与运算符

    • 数值类型
    • 字符串类型
    • 日期时间类型
    • BIT 类型
    • ENUM 类型
    • SET 类型
    • JSON 类型
    • 类型转换
  • 第4章 函数与表达式

    • 字符串函数
    • 数值函数
    • 日期函数
    • 全文检索函数
  • 第5章 高级查询与子查询

    • JOIN
    • 子查询
    • UNION
    • GROUP BY
    • HAVING
    • DISTINCT
  • 第6章 表与索引

    • 数据定义语言
    • 修改表结构
    • 视图
    • 修改视图与检查选项
    • 外键
    • 索引
    • 唯一索引
    • 复合索引
    • 存储引擎对比
    • 分区表
    • 第一范式与第二范式
    • 第三范式与 BC 范式
    • 反范式设计
  • 第7章 存储过程与函数

    • 存储过程
    • 存储函数
    • 变量
    • 流程控制
    • 游标
    • 预处理语句
  • 第8章 事务与锁

    • 事务
    • 事务隔离级别
    • 锁机制
    • MVCC
    • 死锁专题分析
    • LOCK TABLES
    • XA 事务
  • 第9章 用户管理与安全

    • 用户管理
    • 权限管理
    • 角色
    • SQL 注入防范
  • 第10章 性能优化入门

    • 执行计划
    • 索引优化
    • 查询优化
    • 查询优化器提示
    • 慢查询日志
    • InnoDB 深入机制
    • InnoDB 专项优化
    • Performance Schema
    • sys Schema
  • 第11章 复制与高可用

    • 主从复制原理
    • 半同步复制配置
    • binlog 开启与 point-in-time 恢复
    • mysqldump 全库备份
    • mysqldump 单表与条件备份
    • mysqldump 恢复与导入
    • xtrabackup 全量热备
    • xtrabackup 准备与恢复
    • xtrabackup 增量与流式备份
  • 第12章 触发器与事件

    • 触发器
    • 事件调度器
  • 参考

    • MySQL 5.7 专业术语大全
    • MySQL 5.7 关键字与保留字大全

XA 事务

导学

单机事务用 BEGIN ... COMMIT 就能搞定,但分布式系统(如跨库转账、订单+库存同时扣减)需要多个数据库协同。XA 协议是 X/Open 组织定义的分布式事务标准,MySQL 5.7 完整支持 XA 事务,让你能够协调多个资源管理器(如多个 MySQL 实例、甚至异构数据库)完成"要么全成功、要么全回滚"的分布式事务。

定义

XA 事务:基于 X/Open XA 规范的分布式事务协议,将事务拆分为两个阶段(2PC:Two-Phase Commit)。MySQL 作为资源管理器(Resource Manager)参与分布式事务,由外部事务管理器(Transaction Manager)协调。

核心语法

XA 事务语句

-- 1. 启动 XA 事务
XA START 'xid';
-- 或:XA BEGIN 'xid';

-- 2. 执行业务 SQL
INSERT / UPDATE / DELETE ...

-- 3. 结束事务分支
XA END 'xid';

-- 4. 预提交(第一阶段:投票)
XA PREPARE 'xid';

-- 5. 正式提交(第二阶段:提交)
XA COMMIT 'xid';

-- 或回滚
XA ROLLBACK 'xid';

XID 格式

xid: gtrid [, bqual [, formatID ]]
部分说明示例
gtrid全局事务 ID(必填)'order_20240101_001'
bqual分支限定符(可选,区分不同 RM)'db1'、'db2'
formatID格式标识(可选,默认 1)1

完整 XID:XA START 'order_001,db1,1'

演示数据准备

-- 模拟分布式事务的两个"分支"
-- 分支 A:订单库(当前连接)
DROP TABLE IF EXISTS orders;

CREATE TABLE orders (
    order_id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    amount DECIMAL(10,2),
    status ENUM('pending', 'paid', 'cancelled') DEFAULT 'pending'
) ENGINE=InnoDB;

INSERT INTO orders (user_id, amount) VALUES (1001, 199.99);

-- 分支 B:库存库(假设在另一个 MySQL 实例,这里用不同表模拟)
DROP TABLE IF EXISTS inventory;

CREATE TABLE inventory (
    product_id INT PRIMARY KEY,
    stock INT NOT NULL
) ENGINE=InnoDB;

INSERT INTO inventory (product_id, stock) VALUES (2001, 100);

当前数据状态:

orders 表:

order_iduser_idamountstatus
11001199.99pending

inventory 表:

product_idstock
2001100

SQL 示例

场景一:完整的 XA 事务(两阶段提交)

当前数据状态:见上文 orders 和 inventory 表。

执行语句:

-- 步骤 1:启动 XA 事务(全局事务 ID = 'order_001')
XA START 'order_001';

-- 步骤 2:执行业务操作(订单支付 + 库存扣减)
UPDATE orders SET status = 'paid' WHERE order_id = 1;
UPDATE inventory SET stock = stock - 1 WHERE product_id = 2001;

-- 步骤 3:结束事务分支
XA END 'order_001';

-- 步骤 4:预提交(第一阶段)
XA PREPARE 'order_001';

-- 步骤 5:正式提交(第二阶段)
XA COMMIT 'order_001';

操作后结果:

SELECT * FROM orders;
SELECT * FROM inventory;

orders:

order_iduser_idamountstatus
11001199.99paid

inventory:

product_idstock
200199

结果解读:

  • XA START 开启一个 XA 事务分支,绑定全局事务 ID order_001
  • 在 XA 事务中执行普通 SQL,和普通事务一样有 ACID 保证
  • XA END 标记事务分支结束,不再接受新 SQL
  • XA PREPARE 是第一阶段:将事务日志刷盘,告知事务管理器"我已准备好提交,即使崩溃也能恢复"
  • XA COMMIT 是第二阶段:所有资源管理器都 PREPARE 成功后,事务管理器发出最终提交指令
  • 两阶段提交确保分布式事务的原子性:要么所有分支都提交,要么都回滚

场景二:XA 回滚(事务失败时)

当前数据状态:orders 已支付,inventory 库存已扣减。

执行语句:

-- 模拟另一个订单,但中途发现库存不足,需要回滚
XA START 'order_002';

UPDATE orders SET status = 'paid' WHERE order_id = 1;
-- 假设这里检查发现库存不足,决定回滚

XA END 'order_002';
XA PREPARE 'order_002';

-- 事务管理器决定回滚
XA ROLLBACK 'order_002';

操作后结果:

SELECT * FROM orders WHERE order_id = 1;
order_iduser_idamountstatus
11001199.99paid

结果解读:

  • XA ROLLBACK 在 XA PREPARE 之后执行,回滚整个分布式事务
  • 注意:如果 XA PREPARE 已经成功,事务进入"已准备"状态,此时即使连接断开,MySQL 也会保留事务状态,等待事务管理器的 COMMIT 或 ROLLBACK 指令
  • 这是 XA 的核心设计:PREPARE 后,资源管理器承诺"我一定能提交或回滚",即使崩溃也能通过 redo log 恢复

场景三:查看 XA 事务状态(XA RECOVER)

当前数据状态:基于上文。

执行语句:

-- 查看当前处于 PREPARE 状态的 XA 事务
XA RECOVER;

操作后结果(假设有未完成的 XA 事务):

formatIDgtrid_lengthbqual_lengthdata
1103order_001db1

结果解读:

  • XA RECOVER 列出所有处于 PREPARE 状态但未最终提交/回滚的 XA 事务
  • data 列显示完整的 XID(gtrid + bqual 拼接)
  • 这是故障恢复的关键命令:当事务管理器崩溃后重启,通过 XA RECOVER 找到悬而未决的事务,再决定 COMMIT 或 ROLLBACK

场景四:XA 事务的隔离性验证

当前数据状态:orders 表有一条 pending 订单。

执行语句:

-- 会话 A:启动 XA 事务,修改订单状态(未提交)
XA START 'order_003';
UPDATE orders SET status = 'paid' WHERE order_id = 1;

-- 会话 B:尝试查询同一行(默认 REPEATABLE READ)
-- 会被阻塞,直到 XA 事务提交或回滚
SELECT * FROM orders WHERE order_id = 1;

操作后结果:

会话 B 的 SELECT 会等待会话 A 的 XA 事务结束。

结果解读:

  • XA 事务和普通事务一样遵循 InnoDB 的隔离级别(默认 REPEATABLE READ)
  • UPDATE 会加行锁,其他会话的 SELECT ... FOR UPDATE 或 UPDATE 会被阻塞
  • XA PREPARE 后,锁仍然保持,直到 XA COMMIT 或 XA ROLLBACK
  • 这是 XA 的一个风险点:PREPARE 后如果事务管理器长时间不决策,会导致长时间锁等待

常见误区

误区正解
"XA 事务就是普通事务的扩展"不是。XA 是分布式事务协议,需要事务管理器(TM)协调多个资源管理器(RM)。MySQL 只扮演 RM 角色。
"XA 事务性能和普通事务一样"不是。XA 有两阶段提交,网络往返 + 日志刷盘,性能开销大。适合对一致性要求极高的场景,不适合高并发短事务。
"XA PREPARE 后可以断开连接"可以断开,但事务不会消失。MySQL 会保留 PREPARE 状态,等待 TM 的 COMMIT/ROLLBACK。长时间不决策会导致锁不释放。
"XA 事务只支持 InnoDB"是的。MySQL 5.7 中 XA 事务只支持 InnoDB 引擎,MyISAM 不支持事务,无法参与 XA。
"XA 事务可以嵌套普通事务"不能。XA 事务和普通事务互斥。执行 XA START 前必须结束当前普通事务,反之亦然。
"XA 能解决所有分布式一致性问题"不能。XA 保证的是原子性(ACID 的 A),不是全局一致性。网络分区时,TM 可能无法决策,导致事务悬挂。

面试考点

Q:XA 事务的两阶段提交(2PC)流程?

第一阶段(投票):TM 向所有 RM 发送 PREPARE,RM 执行本地事务预提交(日志刷盘),返回 OK 或 NO。第二阶段(决策):如果所有 RM 返回 OK,TM 发送 COMMIT;如果有 RM 返回 NO,TM 发送 ROLLBACK。RM 收到最终指令后执行正式提交或回滚。

Q:XA 事务的悬挂(Heuristic Decision)问题?

如果 TM 在第二阶段崩溃,RM 处于 PREPARE 状态等待指令。如果 TM 长时间不恢复,RM 可能被迫自己做决定(Heuristic Commit/Rollback),破坏原子性。这是 2PC 的固有缺陷,生产环境需要 TM 高可用(如集群部署)来避免。

Q:MySQL XA 和普通事务的区别?

  1. 语法不同:XA 用 XA START/END/PREPARE/COMMIT,普通事务用 BEGIN/COMMIT。2. XA 需要全局事务 ID(XID),普通事务不需要。3. XA 支持分布式协调,普通事务只限单机。4. XA PREPARE 后事务状态持久化,即使断连也能恢复;普通事务断连自动回滚。

Q:XA 事务适合什么场景?

适合跨库/跨服务的强一致性场景,如:银行转账(扣款库 + 收款库)、订单+库存扣减、分布式消息队列的事务消息。不适合:高并发短事务(性能开销大)、单库操作(没必要)、最终一致性可接受的场景(用消息队列更合适)。

Q:MySQL 5.7 XA 和 MySQL 8.0 的区别?

MySQL 8.0 对 XA 的主要改进:1. XA 事务的持久性增强(PREPARE 状态更可靠);2. 支持 XA COMMIT ... ONE PHASE(单阶段提交,优化只涉及一个 RM 的场景);3. 复制兼容性改进(XA 事务的 binlog 格式优化)。核心 2PC 机制不变。

小结

  • XA 是分布式事务的 2PC 标准协议,MySQL 5.7 作为资源管理器(RM)支持
  • 核心流程:XA START → SQL 操作 → XA END → XA PREPARE → XA COMMIT/ROLLBACK
  • XA PREPARE 后事务状态持久化,即使断连也能通过 XA RECOVER 恢复
  • 性能开销大(两阶段 + 网络往返),适合强一致性要求的跨库场景
  • 长时间 PREPARE 不决策会导致锁不释放,需要 TM 高可用保障

下一章引子:XA 事务解决了分布式一致性,但单机性能的极致优化还需要深入 InnoDB 引擎的底层机制——缓冲池、redo log、undo log、锁优化等。

上一页
LOCK TABLES