日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

MySQL的本地事务、全局事务、分布式事务

發(fā)布時(shí)間:2023/10/11 127 老码农
生活随笔 收集整理的這篇文章主要介紹了 MySQL的本地事务、全局事务、分布式事务 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本地事務(wù)

事務(wù)特性:ACID,其中C一致性是目的,AID是手段。

實(shí)現(xiàn)隔離性

寫鎖:數(shù)據(jù)加了寫鎖,其他事務(wù)不能寫也不能讀。

讀鎖:數(shù)據(jù)加了讀鎖,其他事務(wù)不能加寫鎖可以加讀鎖,可以允許自己升級(jí)為寫鎖。

范圍鎖:對(duì)某個(gè)范圍加寫鎖,范圍內(nèi)數(shù)據(jù)不能寫入。

隔離級(jí)別

以鎖為手段來(lái)實(shí)現(xiàn)隔離性才是數(shù)據(jù)庫(kù)表現(xiàn)出不同隔離級(jí)別的根本原因。

可串行化:對(duì)事務(wù)所有讀、寫數(shù)據(jù)加上三種鎖。

可重復(fù)讀:不加范圍鎖,會(huì)有幻讀問題。

幻讀是指在事務(wù)執(zhí)行過程中,兩個(gè)完全相同的范圍查詢得到了不同的結(jié)果集。譬如現(xiàn)在準(zhǔn)備統(tǒng)計(jì)一下 Fenix's Bookstore 中售價(jià)小于 100 元的書有多少本,會(huì)執(zhí)行以下第一條 SQL 語(yǔ)句:

SELECT count(1) FROM books WHERE price < 100					/* 時(shí)間順序:1,事務(wù): T1 */
INSERT INTO books(name,price) VALUES ('深入理解Java虛擬機(jī)',90) /* 時(shí)間順序:2,事務(wù): T2 */
SELECT count(1) FROM books WHERE price < 100 /* 時(shí)間順序:3,事務(wù): T1 */ 兩次執(zhí)行之間有另外一個(gè)事務(wù)在數(shù)據(jù)庫(kù)插入了一本小于 100 元的書籍,那這兩次相同的查詢就會(huì)得到不一樣的結(jié)果,原因是可重復(fù)讀沒有范圍鎖來(lái)禁止在該范圍內(nèi)插入新的數(shù)據(jù),這是一個(gè)事務(wù)受到其他事務(wù)影響,隔離性被破壞的表現(xiàn)。

讀已提交:寫鎖會(huì)一直持續(xù)到事務(wù)結(jié)束,讀鎖在查詢操作完成后馬上釋放。有不可重復(fù)讀問題,讀已提交的隔離級(jí)別缺乏貫穿整個(gè)事務(wù)周期的讀鎖,無(wú)法禁止讀取過的數(shù)據(jù)發(fā)生變化。

讀已提交:有臟讀問題。

MVCC

基本思路是對(duì)數(shù)據(jù)庫(kù)的修改不會(huì)直接覆蓋之前的數(shù)據(jù),而是產(chǎn)生一個(gè)新版副本與老版本共存。

“版本”可以理解為每一行記錄存在倆看不見的字段:CREATE_VERRSION和DELETE_VERSION,這兩個(gè)字段都是事務(wù)ID,事務(wù)ID是全局遞增的值,根據(jù)以下規(guī)則寫入數(shù)據(jù)。

  • 插入數(shù)據(jù):CREATE_VERRSION記錄插入數(shù)據(jù)的事務(wù)ID,DELETE_VERSION為空。
  • 刪除數(shù)據(jù):DELETE_VERSION記錄刪除數(shù)據(jù)的事務(wù)ID,CREATE_VERRSION為空。
  • 修改數(shù)據(jù):將修改數(shù)據(jù)視為“刪除舊數(shù)據(jù),插入新數(shù)據(jù)”,將原有數(shù)據(jù)復(fù)制一份,原有數(shù)據(jù)DELETE_VERSION記錄修改數(shù)據(jù)的事務(wù)ID。復(fù)制出來(lái)的新數(shù)據(jù)CREATE_VERSION記錄修改數(shù)據(jù)的事務(wù)ID。

此時(shí),有另一個(gè)事務(wù)讀取這些發(fā)生了變化的數(shù)據(jù),根據(jù)隔離級(jí)別決定讀取哪個(gè)版本的數(shù)據(jù)。

  • 可重復(fù)讀:在“總是讀取CREATE_VERSION小于等于當(dāng)前事務(wù)ID的數(shù)據(jù)”前提下,如果數(shù)據(jù)有多個(gè)版本,讀取事務(wù)ID最大的。
  • 讀已提交:總是讀取最新版本,即最近被Commit版本的數(shù)據(jù)。

MVCC是針對(duì)“讀+寫”的優(yōu)化,“寫+寫”只能加鎖解決。競(jìng)爭(zhēng)激烈的情況下,樂觀鎖可能更慢。

MVCC超售問題

數(shù)據(jù)庫(kù)采用的是MVCC方案,是否有可能出現(xiàn)以下這種超售情況

初始quantity值為10,事務(wù): T1和事務(wù): T2都想要將quantity減8

SELECT quantity FROM books WHERE id=1					/* 時(shí)間順序:1,事務(wù): T1 */
SELECT quantity FROM books WHERE id=1 /* 時(shí)間順序:2,事務(wù): T2 */ /*事務(wù): T1 運(yùn)算后將quantity改為2 因?yàn)镸VCC方案中事務(wù)2的select并不會(huì)加讀鎖,所以這條語(yǔ)句可以順利執(zhí)行并commit*/
UPDATE books SET quantity=2 WHERE id=1 /* 時(shí)間順序:3,事務(wù): T1 */
commit /*事務(wù): T2 運(yùn)算后將quantity改為2 ,此時(shí)沒有其他的事務(wù)了,所以這條語(yǔ)句可以順利執(zhí)行并commit*/
UPDATE books SET quantity=2 WHERE id=1 /* 時(shí)間順序:4,事務(wù): T2 */
commit

這種寫法會(huì)出現(xiàn)超售,相當(dāng)于賣了兩次8本書。

之前提到過,MVCC只解決“讀-寫”事務(wù)的情況(也就是解決可重復(fù)讀級(jí)別下的幻讀),在“寫-寫”的場(chǎng)景中它是不適用的。

也正是為了解決這類情況,InnoDB之類采用MVCC的引擎,都會(huì)提供諸如“l(fā)ock in share mode”的語(yǔ)法,讓開發(fā)者在“寫-寫”的場(chǎng)

景中顯式加共享鎖,讓數(shù)據(jù)庫(kù)進(jìn)行當(dāng)前讀而非快照讀

以MySQL為例,把代碼修改為這樣,它就可以保證T1的Update語(yǔ)句被T2的共享鎖阻塞了,達(dá)到避免超售的目的了。

SELECT quantity FROM books WHERE id=1 lock in share mode;		/* 時(shí)間順序:1,事務(wù): T1 */
SELECT quantity FROM books WHERE id=1 lock in share mode; /* 時(shí)間順序:2,事務(wù): T2 */

全局事務(wù)

2PC

假如你平時(shí)以聲明式事務(wù)來(lái)編碼,那它與本地事務(wù)看起來(lái)可能沒什么區(qū)別,都是標(biāo)個(gè)@Transactional注解而已,但如果以編程式事務(wù)來(lái)實(shí)現(xiàn)的話,就能在寫法上看出差異,偽代碼如下所示:
public void buyBook(PaymentBill bill) {
userTransaction.begin();
warehouseTransaction.begin();
businessTransaction.begin();
try {
userAccountService.pay(bill.getMoney());
warehouseService.deliver(bill.getItems());
businessAccountService.receipt(bill.getMoney());
userTransaction.commit();
warehouseTransaction.commit();
businessTransaction.commit();
} catch(Exception e) {
userTransaction.rollback();
warehouseTransaction.rollback();
businessTransaction.rollback();
}
}
從代碼上可看出,程序的目的是要做三次事務(wù)提交,但實(shí)際上代碼并不能這樣寫,試想一下,如果在
businessTransaction.commit()中出現(xiàn)錯(cuò)誤,代碼轉(zhuǎn)到catch塊中執(zhí)行,此時(shí)userTransaction和
warehouseTransaction已經(jīng)完成提交,再去調(diào)用rollback()方法已經(jīng)無(wú)濟(jì)于事,這將導(dǎo)致一部分?jǐn)?shù)據(jù)被提
交,另一部分被回滾,整個(gè)事務(wù)的一致性也就無(wú)法保證了。

為了解決這個(gè)問題,XA 將事務(wù)提交拆分成為兩階段過程:

  • 準(zhǔn)備階段:又作投票階段,協(xié)調(diào)者詢問事務(wù)的所有參與者是否準(zhǔn)備好提交,參與者如果準(zhǔn)備好提交則回復(fù)Prepared。對(duì)于數(shù)據(jù)庫(kù)來(lái)說(shuō),準(zhǔn)備操作是在重做日志中記錄全部事務(wù)提交操作所要做的內(nèi)容,不釋放隔離性,繼續(xù)持有鎖。
  • 提交階段:又作執(zhí)行階段,協(xié)調(diào)者在上一階段收到Prepared消息,先自己在本地持久化事務(wù)狀態(tài)為Commit,操作完成之后向所有參與者發(fā)送Commit指令;否則,任意一個(gè)參與者回復(fù)了 Non-Prepared 消息,或任意一個(gè)參與者超時(shí)未回復(fù),協(xié)調(diào)者將將自己的事務(wù)狀態(tài)持久化為 Abort 之后,向所有參與者發(fā)送 Abort 指令,參與者立即執(zhí)行回滾操作。

缺點(diǎn)

  • 單點(diǎn)問題:協(xié)調(diào)者在兩段提交中具有舉足輕重的作用,協(xié)調(diào)者等待參與者回復(fù)時(shí)可以有超時(shí)機(jī)制,允許參與者

    宕機(jī),但參與者等待協(xié)調(diào)者指令時(shí)無(wú)法做超時(shí)處理。一旦宕機(jī)的不是其中某個(gè)參與者,而是協(xié)調(diào)者的話,所有

    參與者都會(huì)受到影響。如果協(xié)調(diào)者一直沒有恢復(fù),沒有正常發(fā)送 Commit 或者 Rollback 的指令,那所有參與

    者都必須一直等待。

  • 性能問題:兩段提交過程中,所有參與者相當(dāng)于被綁定成為一個(gè)統(tǒng)一調(diào)度的整體,期間要經(jīng)過兩次遠(yuǎn)程服務(wù)調(diào)

    用,三次數(shù)據(jù)持久化(準(zhǔn)備階段寫重做日志,協(xié)調(diào)者做狀態(tài)持久化,提交階段在日志寫入 Commit

    Record),整個(gè)過程將持續(xù)到參與者集群中最慢的那一個(gè)處理操作結(jié)束為止,這決定了兩段式提交的性能通

    常都較差。

  • 一致性風(fēng)險(xiǎn)

3PC

三段式提交把原本的兩段式提交的準(zhǔn)備階段細(xì)分為兩個(gè)階段,分別稱為CanCommit、PreCommit,提交階段改為

DoCommit階段。CanCommit是詢問階段,協(xié)調(diào)者讓每個(gè)參與者根據(jù)自身狀態(tài)評(píng)估事務(wù)是否可能完成。

將準(zhǔn)備階段一分為二的理由是:協(xié)調(diào)者發(fā)出開始準(zhǔn)備的消息,參與者開始寫重做日志,如果此時(shí),某一個(gè)參與者宣布無(wú)法完成,相當(dāng)于大家做了一輪無(wú)用功。

因此,在事務(wù)需要回滾的場(chǎng)景中,三段式的性能通常是要比兩段式好很多的,但在事務(wù)能夠正常提交的場(chǎng)景中,兩者的性能都依然很差,甚至三段式因?yàn)槎嗔艘淮卧儐枺€要稍微更差一些。

同樣也是由于事務(wù)失敗回滾概率變小的原因,在三段式提交中,如果在 PreCommit 階段之后發(fā)生了協(xié)調(diào)者宕機(jī),即參與者沒有能等到 DoCommit 的消息的話,默認(rèn)的操作策略將是提交事務(wù)而不是回滾事務(wù)或者持續(xù)等待,這就相當(dāng)于避免了協(xié)調(diào)者單點(diǎn)問題的風(fēng)險(xiǎn)。

分布式事務(wù)

CAP與ACID

柔性事務(wù)與最終一致性。

可靠事件隊(duì)列

最大努力一次提交:將最有可能出錯(cuò)的業(yè)務(wù)以本地事務(wù)的方式完成后,采用不斷重試的方式促使分布式事務(wù)中的其他關(guān)聯(lián)業(yè)務(wù)全部完成。

TCC事務(wù)

如果業(yè)務(wù)需要隔離,該方案天生適合用于需要強(qiáng)隔離性的分布式事務(wù)中。

TCC 較為煩瑣,它是一種業(yè)務(wù)侵入式較強(qiáng)的事務(wù)方案,要求業(yè)務(wù)處理過程必須拆分為“預(yù)留業(yè)務(wù)資源”和“確認(rèn)/釋放消費(fèi)資源”兩個(gè)子過程。如同 TCC 的名字所示,它分為以下三個(gè)階段。

  • Try:嘗試執(zhí)行階段,完成所有業(yè)務(wù)可執(zhí)行性的檢查(保障一致性),并且預(yù)留好全部需用到的業(yè)務(wù)資源(保障隔離性)。
  • Confirm:確認(rèn)執(zhí)行階段,不進(jìn)行任何業(yè)務(wù)檢查,直接使用 Try 階段準(zhǔn)備的資源來(lái)完成業(yè)務(wù)處理。Confirm 階段可能會(huì)重復(fù)執(zhí)行,因此本階段所執(zhí)行的操作需要具備冪等性。
  • Cancel:取消執(zhí)行階段,釋放 Try 階段預(yù)留的業(yè)務(wù)資源。Cancel 階段可能會(huì)重復(fù)執(zhí)行,也需要滿足冪等性。

資料

鳳凰架構(gòu)

總結(jié)

以上是生活随笔為你收集整理的MySQL的本地事务、全局事务、分布式事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。