什么是ACID
在日常操作中,對于一組相關(guān)操作,通常需要其全部成功或全部失敗。
在關(guān)系型數(shù)據(jù)庫中,將這組相關(guān)操作稱為“事務(wù)”。
在一個事務(wù)中,多個插入、修改、刪除操作要么全部成功,要么全部失敗,這稱為“原子性”,實(shí)際上一個事務(wù)還需要有其他三個特性,即“一致性”“隔離性”“持久性”,英文簡稱為“ACID”:
- 原子性(Atomicity):事務(wù)必須以一個整體單元的形式進(jìn)行工作,對于其數(shù)據(jù)的修改,要么全部執(zhí)行,要么全都不執(zhí)行。如果只執(zhí)行事務(wù)中多個操作的前半部分就出現(xiàn)錯誤,那么必須回滾所有的操作,讓數(shù)據(jù)在邏輯上回滾到原先的狀態(tài)
- 一致性(Consistency):在事務(wù)完成時,必須使所有的數(shù)據(jù)都保持在一致狀態(tài)。(AB轉(zhuǎn)賬,A賬戶5000元,不論他怎么轉(zhuǎn)給B,AB賬戶合計(jì)還是5000元,這就是一致性)
- 隔離性(Isolation):事務(wù)查看數(shù)據(jù)時數(shù)據(jù)所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)是不會查看中間狀態(tài)的數(shù)據(jù)的
- 持久性(Durability):事務(wù)完成之后,它對于系統(tǒng)的影響是永久性的,即使今后出現(xiàn)致命的系統(tǒng)故障(如機(jī)器重啟、斷電),數(shù)據(jù)也將一直保持
在PG中,可以使用多版本并發(fā)控制(MVCC)來維護(hù)數(shù)據(jù)的一致性。相比于鎖定模型,其主要優(yōu)點(diǎn)是在MVCC下對檢索(讀)數(shù)據(jù)的鎖請求與寫數(shù)據(jù)的鎖請求不沖突,讀不會阻塞寫,而寫也不會阻塞讀。
在PG中提供了表和行級別的鎖定語句,讓應(yīng)用能更方便地操作并發(fā)數(shù)據(jù)。
DDL事務(wù)
在PG中,與其他數(shù)據(jù)庫最大的不同是,大多數(shù)DDL也是可以包含在一個事務(wù)中的,而且也是可以回滾的。該功能非常適合把PG作為Sharding的分布式數(shù)據(jù)系統(tǒng)的底層數(shù)據(jù)庫。
比如在Sharding中常常需要在多個節(jié)點(diǎn)中建相同的表,此時可以考慮把建表語句放在同一個事務(wù)中,這樣就可以在各個節(jié)點(diǎn)上先啟動一個事務(wù),然后再執(zhí)行建表語句,如果某個節(jié)點(diǎn)執(zhí)行失敗,也可以回滾前面已執(zhí)行建表成功的操作,自然就不會出現(xiàn)部分節(jié)點(diǎn)建表成功,部分節(jié)點(diǎn)建表失敗的情況。
事務(wù)的使用方法
手動設(shè)置
set AUTOCOMMIT off
BEGIN語句
SAVEPOINT
PG支持保存點(diǎn)(SAVEPOINT)的功能,在一個大事務(wù)中,可以把操作過程分為幾個部分,第一個部分執(zhí)行成功后可以建一個保存點(diǎn),若后面的部分執(zhí)行失敗,則回滾到此保存點(diǎn),而不必回滾整個事務(wù)。
事務(wù)隔離級別
數(shù)據(jù)庫的事務(wù)隔離級別有以下4種(不同的數(shù)據(jù)庫可能不同):
- READ UNCOMMITTED:讀未提交
- READ COMMITTED:讀已提交
- REPEATABLE READ:重復(fù)讀
- SERIALIZABLE:串行化
對于并發(fā)事務(wù),我們不希望發(fā)生不一致的情況,這類情況的級別從高到低排序如下:
- 臟讀:一個事務(wù)讀取了另一個未提交事務(wù)寫入的數(shù)據(jù)。這是我們最不希望發(fā)生的,因?yàn)槿绻l(fā)生了臟讀,則在并發(fā)控制上,應(yīng)用程序會變得很復(fù)雜
- 不可重復(fù)讀:指一個事務(wù)重新讀取前面讀取過的數(shù)據(jù)時,發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)被另一個已提交事務(wù)修改了。在大多數(shù)情況下,這還是可以接受的,只是在少數(shù)情況下會出現(xiàn)問題
- 幻讀:一個事務(wù)開始后,需要根據(jù)數(shù)據(jù)庫中現(xiàn)有的數(shù)據(jù)做一些更新,于是重新執(zhí)行一個查詢,返回一套符合查詢條件的行,這時發(fā)現(xiàn)這些行因?yàn)槠渌罱峤坏氖聞?wù)而發(fā)生了改變,此時現(xiàn)有的事務(wù)如果再進(jìn)行下去的話,就可能會導(dǎo)致數(shù)據(jù)在邏輯上的一些錯誤。
不同事務(wù)隔離級別下的行為:
- 讀未提交:臟讀、不可重復(fù)讀、幻讀
- 讀已提交:不可重復(fù)讀、幻讀
- 重復(fù)讀:幻讀
- 可串行化:不會發(fā)生以上行為
對幻讀理解不清楚的,可以參考以下實(shí)例:
幻讀實(shí)例
數(shù)據(jù)準(zhǔn)備
開啟事務(wù)更新數(shù)據(jù)
更新操作執(zhí)行完之后,新開啟一個事務(wù)插入一條數(shù)據(jù)
更新操作事務(wù)提交后,發(fā)現(xiàn)有一條數(shù)據(jù)id=4未更新,像產(chǎn)生了幻覺一樣,這就是幻讀
PG事務(wù)隔離級別
- 9.1版本之前只有讀已提交和可串行化
- 9.1版本之后增加了重復(fù)讀
也就是說在PG中,如果你選擇了讀未提交的級別,實(shí)際上還是讀已提交;如果選擇可重復(fù)讀級別,有可能實(shí)際上仍是可串行化。
PG中默認(rèn)的隔離級別是讀已提交。當(dāng)一個事務(wù)運(yùn)行于這個隔離級別時,執(zhí)行SELECT查詢(沒有FOR UPDATE/SHARE子句)只能看到查詢開始之前已提交的數(shù)據(jù),而無法看到未提交或者查詢期間其他事務(wù)已提交的數(shù)據(jù);可以看到自身所在事務(wù)前面尚未提交的更新結(jié)果。實(shí)際上,SELECT查詢看到的是查詢開始運(yùn)行瞬間的一個快照。
注意:同一個事務(wù)中兩個相鄰的SELECT命令可能看到不同的快照,因?yàn)榭赡苡衅渌聞?wù)在第一個SELECT執(zhí)行完之后,提交了更新結(jié)果。
兩階段提交
PG數(shù)據(jù)庫支持兩階段提交協(xié)議。
在分布式系統(tǒng)中,事務(wù)中往往包含了多臺數(shù)據(jù)庫上的操作,雖然單臺數(shù)據(jù)庫的操作能夠保證原子性,但多臺數(shù)據(jù)庫之間的原子性就需要通過兩階段提交來實(shí)現(xiàn)了,兩階段提交是實(shí)現(xiàn)分布式事務(wù)的關(guān)鍵。
兩階段提交有如下5個步驟:
- 應(yīng)用程序先調(diào)用各臺數(shù)據(jù)庫做一些操作,但不提交事務(wù)。然后應(yīng)用程序調(diào)用事務(wù)協(xié)調(diào)器(該協(xié)調(diào)器可能也是由應(yīng)用自己實(shí)現(xiàn)的)中的提交方法
- 事務(wù)協(xié)調(diào)器將聯(lián)絡(luò)事務(wù)中涉及的每臺數(shù)據(jù)庫,并通知它們準(zhǔn)備提交事務(wù),這是第一階段的開始。PG中一般是調(diào)用PREPARE TRANSACTION命令
- 各臺數(shù)據(jù)庫接收到PREPARE TRANSACTION命令后,如果要返回成功,則數(shù)據(jù)庫必須將自己置于如下狀態(tài):確保后續(xù)能在被要求提交(回滾)事務(wù)的時候提交(回滾)事務(wù),所以PG會將已準(zhǔn)備好提交的信息寫入持久存儲區(qū)中。如果數(shù)據(jù)庫無法完成此事務(wù),它會直接返回失敗給事務(wù)協(xié)調(diào)器
- 事務(wù)協(xié)調(diào)器接收所有數(shù)據(jù)庫的響應(yīng)
- 在第二階段,如果任何一個數(shù)據(jù)庫在第一階段返回失敗,則事務(wù)協(xié)調(diào)器將會發(fā)一個回滾命令ROLLBACK PREPARED給各臺數(shù)據(jù)庫。如果所有數(shù)據(jù)庫的響應(yīng)都是成功的,則向各臺數(shù)據(jù)庫發(fā)送COMMIT PREPARED命令,通知各臺數(shù)據(jù)庫事務(wù)成功
兩階段提交實(shí)例
配置max_prepared_transactions
重啟服務(wù)
二階段提交
- 第一階段:PREPARE TRANSACTION ‘osdba_global_trans_0001’
- 第二階段:COMMIT PREPARED ‘osdba_global_trans_0001’
注意:第一階段結(jié)束后,重啟服務(wù),模擬數(shù)據(jù)庫宕機(jī)。服務(wù)重啟后,第二階段提交,數(shù)據(jù)可以正常查詢。文章來源:http://www.zghlxwxcb.cn/news/detail-443308.html
上述命令osdba_global_trans_0001是兩階段提交中全局事務(wù)的ID,由事務(wù)協(xié)調(diào)器生成(事務(wù)協(xié)調(diào)器會持久化該ID)。PG數(shù)據(jù)庫一旦成功執(zhí)行這條命令,也會把事務(wù)持久化,即使數(shù)據(jù)庫重啟,此事務(wù)也不會回滾或丟失。文章來源地址http://www.zghlxwxcb.cn/news/detail-443308.html
到了這里,關(guān)于PostgreSQL-分布式事務(wù)之兩階段提交的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!