Java面试系列之MySQL XA分布式事务

2022-09-23 18:00:11 浏览数 (1)

1.什么是分布式事务?

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败,本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

2.为什么需要分布式事务?

当数据库单表一年产生的数据超过1000W,那么就要考虑分库分表,具体分库分表的原理在此不做解释,以后有空详细说,简单的说就是原来的一个数据库变成了多个数据库。这时候,如果一个操作既访问01库,又访问02库,而且要保证数据的一致性,那么就要用到分布式事务,本质上去讲就是需要确保跨数据源或者跨实例的数据读和写的一致性。

3.为什么只有MySQL的InnoDB存储引擎支持分布式事务?

通过查阅MySQL官网,我们可以发现MySQL XA分布式事务只在InnoDB存储引擎中生效,这个是很好理解的,MySQL支持多种存储引擎,但是只有InnoDB存储引擎是支持事务的(本地事务),而XA分布式事务又是建立在本地事务基础之上的。

4.什么是事务的ACID特性

ACID是指原子性(A)、一致性(C)、隔离性(I)和持久性(D):

  • 原子性,所谓的原子性就是说,在整个事务中的所有操作,要么全部完成,要么全部不做,没有中间状态。对于事务在执行中发生错误,所有的操作都会被回滚,整个事务就像从没被执行过一样;
  • 一致性,事务的执行必须保证系统的一致性,就拿转账为例,A有500元,B有300元,如果在一个事务里A成功转给B50元,那么不管并发多少,不管发生什么,只要事务执行成功了,那么最后A账户一定是450元,B账户一定是350元;
  • 隔离性,所谓的隔离性就是说,事务与事务之间不会互相影响,一个事务的中间状态不会被其他事务感知;
  • 持久性,所谓的持久性,就是说一单事务完成了,那么事务对数据所做的变更就完全保存在了数据库中,即使发生停电,系统宕机也是如此。

5.XA事务是MySQL独有的特性吗?

答案肯定不是的,XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2、MySQL等这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。

XA事务就是两阶段提交的一种实现方式,XA规范主要定义了事务管理器TM,和资源管理器RM之间的接口,根据2PC的规范,将一次事务分割成两个阶段:

  • prepare阶段

TM向所有RM发送prepare指令,RM接受到指令后执行数据修改和日志记录等操作,然后返回 可以提交/不可提交 给TM(按照我的理解应该类似于MySQL在开启一个事务之后,只差最后的COMMIT或者ROLLBACK的状态);

  • commit阶段

TM接受到所有RM的prepare结果,如果有RM返回是 不可提交 或者超时,那么向所有RM发送ROLLBACK命令;如果所有RM都返回可以提交,那么向所有RM发送COMMIT命令。

6.在MySQL中,什么是内部XA?什么是外部XA?

在使用innodb作为存储引擎,并且开启binlog的情况下,MySQL同时维护了binlog日志与innodb的redo log,为了保证这两个日志的一致性,MySQL使用了XA事务,由于只在单机上工作,所以被称为内部XA。

外部XA就是指分布式事务,MySQL支持XA START/END/PREPARE/COMMIT这些sql语句,通过使用这些命令,我们是可以完成分布式事务的状态转移。

在使用innodb作为存储引擎,并且开启binlog的情况下,MySQL同时维护了binlog日志与innodb的redo log,为了保证这两个日志的一致性,MySQL使用了XA事务,由于只在单机上工作,所以被称为内部XA。

外部XA就是指分布式事务,MySQL支持XASTART/END/PREPARE/COMMIT这些sql语句,通过使用这些命令,我们是可以完成分布式事务的状态转移。

在MySQL中XA事务的状态有如下几种:

  • 使用XA START语句启动XA事务,并将其置于ACTIVE状态;
  • 对于ACTIVE XA事务,执行构成该事务的SQL语句,然后执行XA END语句,XA END语句将事务置于IDLE状态;
  • 对于IDLE XA事务,可以执行XA PREPARE或XA COMMIT语句,去完成XA事务第一阶段的声明:(1)XA PREPARE将事务置于PREPARED状态。在此状态下,执行XA RECOVER语句可以获取所有事务的xid值,因为XA RECOVER语句可以列出处于PREPARED状态的所有XA事务;(2)XA提交,第一阶段准备并提交事务。在此状态下,执行XA RECOVER不能获取事务的xid值,因为此时XA事务已经终止了。
  • 对于PREPARED XA事务,可以执行XA COMMIT语句来提交并终止事务,或者执行XA ROLLBACK语句来回滚并终止事务。

详情可以参考官网https://dev.mysql.com/doc/refman/8.0/en/xa-states.html

7.MySQL的XA事务的声明包括哪些步骤?

代码语言:javascript复制
//开启一个XA事务,xid为这个XA事务的全局唯一ID
XA {START|BEGIN} xid [JOIN|RESUME]
//执行XA END语句,将XA事务设置为IDLE状态
XA END xid [SUSPEND [FOR MIGRATE]]
//执行XA PREPARE语句,将XA事务设置为PREPARE状态
XA PREPARE xid
//执行XA COMMIT语句,提交XA事务
XA COMMIT xid [ONE PHASE]
//执行XA ROLLBACK语句,回滚XA事务
XA ROLLBACK xid
//执行XA RECOVER语句,获取所有处于PREPARE状态中的分布式事务XID
XA RECOVER [CONVERT XID]

详情可以参考官网https://dev.mysql.com/doc/refman/5.7/en/xa-statements.html

8.一般我们在MySQL的哪个版本中使用XA事务?

答案是5.7.7和之后的版本,为什么了?主要是5.7.7之前的版本不支持XA事务的持久化,也就是说XA事务的内容没有写二进制文件中。

详情可以参考官网https://dev.mysql.com/doc/refman/5.7/en/xa-restrictions.html

9.在5.7.7和之后的版本中使用MySQL的XA事务,存在哪些坑点呢?

(1)坑点一,XA 事务不能完全适应二进制日志的意外停止。如果在服务器正在执行 XA PREPARE、XA COMMIT、XA ROLLBACK 或 XA COMMIT ... ONE PHASE 语句时出现意外停止,则服务器可能无法恢复到正确状态,从而导致服务器和二进制日志处于不一致的状态。在这种情况下,二进制日志可能包含未应用的额外 XA 事务,或遗漏已应用的 XA 事务。此外,如果启用了 GTID,则在恢复后 @@GLOBAL.GTID_EXECUTED 可能无法正确描述已应用的事务。请注意,如果在 XA PREPARE 之前、XA PREPARE 和 XA COMMIT(或 XA ROLLBACK)之间或 XA COMMIT(或 XA ROLLBACK)之后发生意外停止,则服务器和二进制日志将正确恢复并进入一致状态;

(2)坑点二,不支持将复制过滤器或二进制日志过滤器与 XA 事务结合使用。过滤表可能会导致副本上的 XA 事务为空,并且不支持空 XA 事务。此外,通过在副本上设置 master_info_repository=TABLE 和 relay_log_info_repository=TABLE(在 MySQL 8.0 中成为默认设置),数据引擎事务的内部状态会在过滤的 XA 事务之后发生更改,并且可能与复制事务上下文状态不一致.每当 XA 事务受到复制过滤器的影响时,无论该事务是否因此为空,都会记录错误 ER_XA_REPLICATION_FILTERS。如果事务不为空,则副本能够继续运行,但您应该采取措施停止对 XA 事务使用复制过滤器以避免潜在问题。如果事务为空,则副本停止。在这种情况下,副本可能处于未确定状态,其中复制过程的一致性可能会受到影响。特别是,副本的副本上的 gtid_executed 集可能与源上的不一致。要解决这种情况,请隔离源并停止所有复制,然后检查复制拓扑中的 GTID 一致性。撤消生成错误消息的 XA 事务,然后重新启动复制;

(3)坑点三,在 MySQL 5.7.19 之前,FLUSH TABLES WITH READ LOCK 与 XA 事务不兼容;

(4)坑点四,XA 事务对于基于语句的复制被认为是不安全的。如果在数据源上并行提交的两个 XA 事务正在以相反的顺序在副本上准备,则可能会发生无法安全解决的锁定依赖关系,并且复制可能会因副本上的死锁而失败。这种情况可能发生在单线程或多线程副本上。当设置 binlog_format=STATEMENT 时,会针对 XA 事务中的 DML 语句发出警告。当 binlog_format=MIXED 或 binlog_format=ROW 设置时,XA 事务中的 DML 语句使用基于行的复制进行记录,并且不存在潜在问题。

详情可以参考官网https://dev.mysql.com/doc/refman/5.7/en/xa-restrictions.html

10.怎么使用MySQL的XA分布式事务?

可以使用Spring Boot提供的spring-boot-starter-jta-atomikos组件,去开启MySQL的XA分布式事务。

详情可以参考官网https://docs.spring.io/spring-boot/docs/current/reference/html/index.html

公众号初衷

知识输出是笔者的初衷,借助知识输出,能够认识更多的牛人,能够和牛人沟通,也是自己技术提升的一个机会。

0 人点赞