在开发中,为了降低单点压力,通常会根据业务情况进行分表分库,将表分布在不同的库中(库可能分布在不同的机器上),但是一个业务场景可能会同时处理两个表的操作。在这种场景下,事务的提交会变得相对复杂,因为多个节点(库)的存在,可能存在部分节点提交失败的情况,即事务的ACID特性需要在各个不同的数据库实例中保证。比如更新db1库的A表时,必须同步更新db2库的B表,两个更新形成一个事务,要么都成功,要么都失败。
那么我们如何利用mysql实现分布式数据库的事务呢?

mysql好像是从5.0开始支持分布式事务

这里先声明两个概念:

资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。
事务管理器(transaction manager):事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器(resource
manager)进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识。
mysql在执行分布式事务(外部XA)的时候,mysql服务器相当于xa事务资源管理器,与mysql链接的客户端相当于事务管理器。

分布式事务原理:分段式提交
分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过2PC协议将提交分成两个阶段:

prepare;
commit/rollback
阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager报告已准备就绪。
阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

事务协调者transaction manager
因为XA 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。MySQL 在这个XA事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。

Mysql的XA事务分为外部XA和内部XA
外部XA用于跨多MySQL实例的分布式事务,需要应用层作为协调者,通俗的说就是比如我们在PHP中写代码,那么PHP书写的逻辑就是协调者。应用层负责决定提交还是回滚,崩溃时的悬挂事务。MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:网易的DDB,淘宝的TDDL等等。
内部XA事务用于同一实例下跨多引擎事务,由Binlog作为协调者,比如在一个存储引擎提交时,需要将提交信息写入二进制日志,这就是一个分布式内部XA事务,只不过二进制日志的参与者是MySQL本身。Binlog作为内部XA的协调者,在binlog中出现的内部xid,在crash recover时,由binlog负责提交。(这是因为,binlog不进行prepare,只进行commit,因此在binlog中出现的内部xid,一定能够保证其在底层各存储引擎中已经完成prepare)。

mysql xa事务的语法

1、首先要确保mysql开启XA事务支持

SHOW VARIABLES LIKE '%xa%'

如果innodb_support_xa的值是ON就说明mysql已经开启对XA事务的支持了。

如果不是就执行:

SET innodb_support_xa = ON

主要有:

XA START 'any_unique_id'; // 'any_unique_id' 是用户给的,全局唯一在一台mysql中开启一个XA事务
XA END 'any_unique_id '; //标识XA事务的操作结束
XA PREPARE 'any_unique_id'; //告知mysql 准备提交这个xa事务
XA COMMIT 'any_unique_id'; //告知mysql提交这个xa事务
XA ROLLBACK 'any_unique_id'; //告知mysql回滚这个xa事务
XA RECOVER;//查看本机mysql目前有哪些xa事务处于prepare状态

XA事务恢复
如果执行分布式事务的mysql crash了,mysql 按照如下逻辑进行恢复:
a. 如果这个xa事务commit了,那么什么也不用做
b. 如果这个xa事务还没有prepare,那么直接回滚它
c. 如果这个xa事务prepare了,还没commit, 那么把它恢复到prepare的状态,由用户去决定commit或rollback
当mysql crash后重新启动之后,执行“XA RECOVER;”查看当前处于prepare状态的xa事务,然后commit或rollback它们。

使用限制
a. XA事务和本地事务以及锁表操作是互斥的
开启了xa事务就无法使用本地事务和锁表操作

mysql> xa start 't1xa';
Query OK, rows affected (0.04 sec)
mysql> begin;
ERROR (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
mysql> lock table t1 read;
ERROR (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state

开启了本地事务就无法使用xa事务

mysql> begin;
Query OK, rows affected (0.00 sec)
mysql> xa start 'rrrr';
ERROR (XAE09): XAER_OUTSIDE: Some work is done outside global transaction

b. xa start 之后必须xa end, 否则不能执行xa commit 和xa rollback

所以如果在执行xa事务过程中有语句出错了,你也需要先xa end一下,然后才能xarollback。

注意事项
a. mysql只是提供了xa事务的接口,分布式事务中的mysql实例之间是互相独立的不感知的。 所以用户必须
自己实现分布式事务的调度器
b. xa事务有一些使用上的bug, 参考http://www.mysqlops.com/2012/02/24/mysql-xa-optimize.html
主要是
“MySQL数据库的主备数据库的同步,通过Binlog的复制完成。而Binlog是MySQL数据库内部XA事务的协调者,并且MySQL数据库为binlog做了优化——binlog不写prepare日志,只写commit日志。
所有的参与节点prepare完成,在进行xa commit前crash。crash recover如果选择commit此事务。由于binlog在prepare阶段未写,因此主库中看来,此分布式事务最终提交了,但是此事务的操作并未 写到binlog中,因此也就未能成功复制到备库,从而导致主备库数据不一致的情况出现。
而crash recover如果选rollback, 那么就会出现全局不一致(该分布式事务对应的节点,部分已经提交,无法回滚,而部分节点回滚。最终导致同一分布式事务,在各参与节点,最终状态不一致)”

参考的那篇blog中给出的办法是修改mysql代码,这个无法在DBScale中使用。 所以可选的替代方案是不使用
主从复制进行备份,而是直接使用xa事务实现同步写来作为备份。

php+mysql实现分布式事务案例

保证数据表是innodb的

//db_finance库下
CREATE TABLE `t_user_account` (
`id` int() NOT NULL AUTO_INCREMENT COMMENT 'id',
`username` varchar() NOT NULL DEFAULT '' COMMENT '用户名',
`money` int() NOT NULL DEFAULT '' COMMENT '账户金额',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8;
//db_order库下
CREATE TABLE `t_user_orders` (
`id` int() NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar() NOT NULL DEFAULT '',
`money` int() NOT NULL DEFAULT '' COMMENT '订单扣款金额',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8;

php代码

$username = '温柔的风';
$order_money = ; $addOrder_success = addOrder($username,$order_money);
$upAccount_success = updateAccount($username,$order_money); if($addOrder_success['state'] =="yes" && $upAccount_success['state']=="yes"){
commitdb($addOrder_success['xa']);
commitdb1($upAccount_success['xa']);
}else{
rollbackdb($addOrder_success['xa']);
rollbackdb1($upAccount_success['xa']);
}
die;
function addOrder ($username, $order_money){ $xa = uniqid(""); $sql_xa = "XA START '$xa'";
$db = Yii::app()->dborder_readonly;
$db->createCommand($sql_xa)->execute(); $insert_sql = "INSERT INTO t_user_orders (`username`,`money`) VALUES ($username,$order_money)";
$id = $db->createCommand($insert_sql)->execute(); $db->createCommand("XA END '$xa'")->execute();
if ($id) { $db->createCommand("XA PREPARE '$xa'")->execute();
return ['state' => 'yes', 'xa' => $xa];
}else {
return ['state' => 'no', 'xa' => $xa];
} } function updateAccount($username, $order_money){
$xa = uniqid("");
$sql_xa = "XA START '$xa'";
$db = Yii::app()->db_finance;
$db->createCommand($sql_xa)->execute(); $sql = "update t_user_account set money=money-".$order_money." where username='$username'"; $id = $db->createCommand($sql)->execute(); $db->createCommand("XA END '$xa'")->execute();
if ($id) {
$db->createCommand("XA PREPARE '$xa'")->execute();
return ['state' => 'yes', 'xa' => $xa];
}else {
return ['state' => 'no', 'xa' => $xa];
} } //提交事务!
function commitdb($xa){ $db = Yii::app()->dborder_readonly;
return $db->createCommand("XA COMMIT '$xa'")->execute();
} //回滚事务
function rollbackdb($xa){ $db = Yii::app()->dborder_readonly;
return $db->createCommand("XA COMMIT '$xa'")->execute();
} //提交事务!
function commitdb1($xa){ $db = Yii::app()->db_finance;
return $db->createCommand("XA COMMIT '$xa'")->execute(); }
//回滚事务
function rollbackdb1($xa){
$db = Yii::app()->db_finance;
return $db->createCommand("XA ROLLBACK '$xa'")->execute(); }

了解一下Mysql分布式事务及优缺点、使用案例(php+mysql)的更多相关文章

  1. Mysql分布式事务

    关于Mysql分布式事务介绍,可参考:http://blog.csdn.net/luckyjiuyi/article/details/46955337 分为两个阶段:准备和执行阶段.有两个角色:事务的 ...

  2. mysql 分布式事务

    php + mysql 分布式事务 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元: 事务应该具有4个属性:原子性.一致性.隔离性.持续性 原子性(atomicit ...

  3. JTA 使用 MySQL 分布式事务

    假定在MySQL实例1上有表 create table person( id int, name ) ) MySQL实例2上也有一张同样的表,现在从实例1中的 person 表中删除一条数据,并把这条 ...

  4. 详解Mysql分布式事务XA(跨数据库事务)

    详解Mysql分布式事务XA(跨数据库事务) 学习了:http://blog.csdn.net/soonfly/article/details/70677138 mysql执行XA事物的时候,mysq ...

  5. MySQL数据库分布式事务XA优缺点与改进方案

    1 MySQL 外部XA分析 1.1 作用分析 MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:ameoba[4],网易的DDB,淘宝的 ...

  6. DTP模型之一:(XA协议之三)MySQL数据库分布式事务XA优缺点与改进方案

    1 MySQL 外部XA分析 1.1 作用分析 MySQL数据库外部XA可以用在分布式数据库代理层,实现对MySQL数据库的分布式事务支持,例如开源的代理工具:ameoba[4],网易的DDB,淘宝的 ...

  7. php + mysql 分布式事务(转)

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元: 事务应该具有4个属性:原子性.一致性.隔离性.持续性 原子性(atomicity).一个事务是一个不可分割的工作单 ...

  8. php + mysql 分布式事务

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元: 事务应该具有4个属性:原子性.一致性.隔离性.持续性 原子性(atomicity).一个事务是一个不可分割的工作单 ...

  9. 分布式事务框架 Seata 入门案例

    1.  Seata Server 部署 Seata分TC.TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成. 首先,下载最新的安装包 也可以下载源 ...

随机推荐

  1. Linux跨网段通信小实验

    一.实验场景. 实验准备,Linux主机4台.分别是主机A,路由主机R1,路由主机R2,主机 C,主机A的ip是192.168.56.66/24,且只有一块网卡eth0:路由主机R1有两块网卡eth0 ...

  2. 数据结构之队列and栈总结分析

    一.前言: 数据结构中队列和栈也是常见的两个数据结构,队列和栈在实际使用场景上也是相辅相成的,下面简单总结一下,如有不对之处,多多指点交流,谢谢. 二.队列简介 队列顾名思义就是排队的意思,根据我们的 ...

  3. Netty学习篇⑤--编、解码

    前言 学习Netty也有一段时间了,Netty作为一个高性能的异步框架,很多RPC框架也运用到了Netty中的知识,在rpc框架中丰富的数据协议及编解码可以让使用者更加青睐: Netty支持丰富的编解 ...

  4. nyoj 78-圈水池 (凸包)

    78-圈水池 内存限制:64MB 时间限制:3000ms 特判: No 通过数:5 提交数:6 难度:4 题目描述: 有一个牧场,牧场上有很多个供水装置,现在牧场的主人想要用篱笆把这些供水装置圈起来, ...

  5. 实现websocket 主动消息推送,用laravel+Swoole

    近来有个需求:想实现一个可以主动触发消息推送的功能,这个可以实现向模板消息那个,给予所有成员发送自定义消息,而不需要通过客户端发送消息,服务端上message中监听传送的消息进行做相对于的业务逻辑. ...

  6. libwebsocket协议切换状态机

    libwebsocket为连接(connection)定义了一组状态机-lws_connection_states,通过状态机我们来看libwebsocket如何实现协议的切换.除了lws_conne ...

  7. 小白学习React官方文档看不懂怎么办?2.JSX语法

      接下来我们就要讲到JSX语法了,在我们讲它之前,我们先引入一个概念叫语法糖.     听到这个名字首先我们可能会想到一个词叫”糖衣炮弹“,那么什么叫糖衣炮弹呢,就是给你说各种好听的话,来迷惑你,但 ...

  8. 浅谈Linux中的各种锁及其基本原理

    本文首发于:https://mp.weixin.qq.com/s/Ahb4QOnxvb2RpCJ3o7RNwg 微信公众号:后端技术指南针 0.概述 通过本文将了解到如下内容: Linux系统的并行性 ...

  9. Java虚拟机之栈

    一.程序计数器(寄存器):PCR 作用:记住下一条JVM指令的执行地址. 特点:①线程私有的 ②不会存在内存溢出 二.虚拟机栈 1.定义 虚拟机栈:线程运行所需要的内存空间. 栈帧:一个栈帧对应一个方 ...

  10. 2019-11-3:渗透测试,基础学习,bypass类型笔记

    等价字符 空格:%20,+,(),%0a,%09,%a0,%0b,%0c,%0d,/**/等 =:like,regexp,liker,<>,! =等 and:&& or:x ...