中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Mysql中如何實現分布式事務

發布時間:2021-06-21 17:57:29 來源:億速云 閱讀:387 作者:Leah 欄目:大數據

今天就跟大家聊聊有關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, 0 rows affected (0.04 sec)
mysql> begin;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
mysql> lock table t1 read;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state

開啟了本地事務就無法使用xa事務

mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> xa start 'rrrr';
ERROR 1400 (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(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(255) NOT NULL DEFAULT '' COMMENT '用戶名',
  `money` int(11) NOT NULL DEFAULT '0' COMMENT '賬戶金額',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
//db_order庫下
CREATE TABLE `t_user_orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `username` varchar(255) NOT NULL DEFAULT '',
  `money` int(11) NOT NULL DEFAULT '0' COMMENT '訂單扣款金額',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8;

php代碼

$username = '溫柔的風';
$order_money = 100;

$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中如何實現分布式事務有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

麻阳| 郑州市| 闽清县| 南漳县| 九江县| 望奎县| 和田市| 凤阳县| 无极县| 宁陵县| 库尔勒市| 开封县| 横山县| 长汀县| 个旧市| 娱乐| 新昌县| 新津县| 东宁县| 醴陵市| 清镇市| 若尔盖县| 柯坪县| 平陆县| 南陵县| 吉水县| 巴林左旗| 游戏| 康马县| 宁陵县| 双鸭山市| 同心县| 商水县| 海林市| 石嘴山市| 西平县| 澳门| 上饶县| 科尔| 南康市| 通城县|