溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何解決Mysql分布式事務(wù)問(wèn)題

發(fā)布時(shí)間:2021-12-04 10:09:44 來(lái)源:億速云 閱讀:191 作者:iii 欄目:云計(jì)算

本篇內(nèi)容介紹了“如何解決Mysql分布式事務(wù)問(wèn)題”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

背景

2020 年 4 月,我們開(kāi)始嘗試實(shí)現(xiàn) go 語(yǔ)言的分布式事務(wù)框架 Seata-Golang。眾所周知,Seata AT 模式以無(wú)業(yè)務(wù)代碼侵入的特點(diǎn),被廣大開(kāi)發(fā)者推崇。Java 版 Seata AT 模式通過(guò)對(duì) DataSource 數(shù)據(jù)源進(jìn)行代理,在 sql 語(yǔ)句執(zhí)行時(shí),對(duì) sql 攔截解析,獲取數(shù)據(jù)庫(kù)對(duì)應(yīng)數(shù)據(jù)在 sql 語(yǔ)句執(zhí)行前后的副本,序列化后保存起來(lái),在 TC 協(xié)調(diào)回滾時(shí)用來(lái)回滾對(duì)應(yīng)數(shù)據(jù)。實(shí)現(xiàn) go 版本 client 的 AT 模式時(shí),怎樣對(duì)業(yè)務(wù)開(kāi)發(fā)者更友好,入侵更少,成了首要考慮的目標(biāo)。

如何解決Mysql分布式事務(wù)問(wèn)題

使用 go 操作數(shù)據(jù)庫(kù)時(shí),我們會(huì)使用到 go 語(yǔ)言的官方庫(kù) database/sql,通過(guò) sql.Open("mysql", ${dsn}) 獲取一個(gè)數(shù)據(jù)源操作對(duì)象 db。開(kāi)啟事務(wù)時(shí),使用 db.Begin() 或 db.BeginTx(ctx, &sql.TxOptions{}) 獲得事務(wù)操作對(duì)象 tx,執(zhí)行 sql 查詢使用 tx.Query;執(zhí)行 sql 新增、修改、刪除,使用 tx.Exec;最后使用 tx.Commit() 提交或使用 tx.Rollback() 回滾。

go 語(yǔ)言官方庫(kù) database/sql 提供了一個(gè)標(biāo)準(zhǔn)抽象層,通過(guò)實(shí)現(xiàn)不同的 driver 一套標(biāo)準(zhǔn)的抽象 API 可以操作不同的數(shù)據(jù)庫(kù)。開(kāi)發(fā) Go 版本的 AT 模式,必然要兼容 database/sql。通過(guò)研究 database/sql 的 api,創(chuàng)建數(shù)據(jù)源操作對(duì)象,數(shù)據(jù)庫(kù)有關(guān)的配置必須通過(guò) Data Source Name (DSN) 抽象傳遞進(jìn)去,下面是 DSN 的定義:

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...?mN=valueN]

實(shí)現(xiàn) AT 模式對(duì)數(shù)據(jù)源代理是需要和事務(wù)協(xié)調(diào)器 TC 進(jìn)行交互的,如果將 AT 模式實(shí)現(xiàn)在 driver 層,那么和 TC 交互的一些參數(shù)必須要通過(guò) DSN 傳遞到 driver,這樣有些破壞它的設(shè)計(jì)。所以,最后采取了一種折中方案,在 database/sql 層之上實(shí)現(xiàn) AT 模式,代理 database/sql 創(chuàng)建出來(lái)的數(shù)據(jù)源操作對(duì)象。數(shù)據(jù)源代理對(duì)象實(shí)現(xiàn) database/sql 庫(kù)定義的 Tx 接口,另外再提供一個(gè)開(kāi)啟事務(wù)的方法:Begin(),雖然沒(méi)有完全兼容 database/sql 的 api,但是關(guān)鍵接口和它的定義成一樣,勉強(qiáng)還能接受。到此,Seata-Golang 項(xiàng)目核心功能的開(kāi)發(fā)已完成。

type Tx interface {
    Commit() error
    Rollback() error
}

轉(zhuǎn)折

Seata-Golang 開(kāi)源后,逐漸被一些開(kāi)發(fā)者了解和接觸,社區(qū)也對(duì) Seata-Golang 發(fā)出了一些反饋的聲音,不少開(kāi)發(fā)者并不習(xí)慣寫原生 sql,他們希望將 Seata-Golang 集成到 ORM 框架,因?yàn)楫?dāng)時(shí)的設(shè)計(jì)沒(méi)有完全兼容 database/sql 導(dǎo)致集成上遇到一些困難。隨著社區(qū)的熱切呼喚,且得益于前期對(duì) driver 的一些研究,念念不忘必有回響,今年 3 月突然靈感迸發(fā):為什么參數(shù)一定要通過(guò) DSN 傳遞?Seata-Golang Client 初始化后,在需要時(shí)通過(guò) Client 端的 API config.GetATConfig() 直接獲取使用不就可以了。

如何解決Mysql分布式事務(wù)問(wèn)題

于是工作之余,歷時(shí) 2 周開(kāi)發(fā),第一個(gè)集成 Seata-Golang 的完全兼容 database/sql 的 mysql driver 被開(kāi)發(fā)出來(lái)

driver 的一些細(xì)節(jié)

  • 使用該 driver 進(jìn)行分布式事務(wù)操作時(shí),不能在 dsn 中設(shè)置 interpolateParams 參數(shù)為 true。

這涉及到 mysql 的兩個(gè)協(xié)議:Text 協(xié)議和 Binary 協(xié)議。有關(guān)兩個(gè)協(xié)議的區(qū)別,可以在文末參考文檔找到資料。實(shí)現(xiàn)該 driver 只對(duì) binary 協(xié)議進(jìn)行了處理,開(kāi)啟 interpolateParams 會(huì)使用 text 協(xié)議執(zhí)行 sql。

  • 使用該 driver 在需要加入全局事務(wù)組和 tc 進(jìn)行交互時(shí),需要使用 db.BeginTx(ctx context.Context, opts driver.TxOptions) 方法,并在 ctx 中加入 XID 全局事務(wù) id 的值。

ctx := context.WithValue(context.Background(), mysql.XID, c.Request.Header.Get("XID"))
tx, err := dao.BeginTx(ctx, &sql.TxOptions{
        Isolation: sql.LevelDefault,
        ReadOnly:  false,
    })

XID 傳遞到 driver 層,會(huì)保存在 &mysqlConn 連接對(duì)象中,在和 TC 交互時(shí)用到。

  • 使用該 driver 的分布式事務(wù)功能前需要先初始化 seata-golang client 和 mysql driver

config.InitConf(configPath)
  client.NewRpcClient()
  mysql.InitDataResourceManager()
  mysql.RegisterResource(config.GetATConfig().DSN)

“如何解決Mysql分布式事務(wù)問(wèn)題”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI