PostgreSQL數(shù)據(jù)庫(kù)系統(tǒng)在多個(gè)會(huì)話試圖同時(shí)訪問(wèn)同一數(shù)據(jù)時(shí)的行為。 這種情況的目標(biāo)是為所有會(huì)話提供高效的訪問(wèn),同時(shí)還要維護(hù)嚴(yán)格的數(shù)據(jù)完整性。
- PostgreSQL為開(kāi)發(fā)者提供了一組豐富的工具來(lái)管理對(duì)數(shù)據(jù)的并發(fā)訪問(wèn)。在內(nèi)部,數(shù)據(jù)一致性通過(guò)使用一種多版本模型(多版本并發(fā)控制,MVCC)來(lái)維護(hù)。這就意味著每個(gè) SQL 語(yǔ)句看到的都只是一小段時(shí)間之前的數(shù)據(jù)快照(一個(gè)數(shù)據(jù)庫(kù)版本),而不管底層數(shù)據(jù)的當(dāng)前狀態(tài)。這樣可以保護(hù)語(yǔ)句不會(huì)看到可能由其他在相同數(shù)據(jù)行上執(zhí)行更新的并發(fā)事務(wù)造成的不一致數(shù)據(jù),為每一個(gè)數(shù)據(jù)庫(kù)會(huì)話提供事務(wù)隔離。MVCC避免了傳統(tǒng)的數(shù)據(jù)庫(kù)系統(tǒng)的鎖定方法,將鎖爭(zhēng)奪最小化來(lái)允許多用戶環(huán)境中的合理性能。
- 使用MVCC并發(fā)控制模型而不是鎖定的主要優(yōu)點(diǎn)是在MVCC中,對(duì)查詢(讀)數(shù)據(jù)的鎖請(qǐng)求與寫數(shù)據(jù)的鎖請(qǐng)求不沖突,所以讀不會(huì)阻塞寫,而寫也從不阻塞讀。甚至在通過(guò)使用革新的可序列化快照隔離(SSI)級(jí)別提供最嚴(yán)格的事務(wù)隔離級(jí)PostgreSQL也維持這個(gè)保證。
事務(wù)隔離
- 臟讀
一個(gè)事務(wù)讀取了另一個(gè)并行未提交事務(wù)寫入的數(shù)據(jù)。
- 不可重復(fù)讀
一個(gè)事務(wù)重新讀取之前讀取過(guò)的數(shù)據(jù),發(fā)現(xiàn)該數(shù)據(jù)已經(jīng)被另一個(gè)事務(wù)(在初始讀之后提交)修改。
- 幻讀
一個(gè)事務(wù)重新執(zhí)行一個(gè)返回符合一個(gè)搜索條件的行集合的查詢, 發(fā)現(xiàn)滿足條件的行集合因?yàn)榱硪粋€(gè)最近提交的事務(wù)而發(fā)生了改變。
- 序列化異常
成功提交一組事務(wù)的結(jié)果與這些事務(wù)所有可能的串行執(zhí)行結(jié)果都不一致。
| 隔離級(jí)別 | 臟讀 | 不可重復(fù)讀 | 幻讀 | 序列化異常 |
|---|---|---|---|---|
| 讀未提交 | 允許,但不在 PG中 | 可能 | 可能 | 可能 |
| 讀已提交 | 不可能 | 可能 | 可能 | 可能 |
| 可重復(fù)讀 | 不可能 | 不可能 | 允許,但不在 PG中 | 可能 |
| 可序列化 | 不可能 | 不可能 | 不可能 | 不可能 |
要設(shè)置一個(gè)事務(wù)的事務(wù)隔離級(jí)別,使用SET TRANSACTION命令。
讀已提交隔離級(jí)別
讀已提交是PostgreSQL中的默認(rèn)隔離級(jí)別。當(dāng)一個(gè)事務(wù)運(yùn)行使用這個(gè)隔離級(jí)別時(shí), 一個(gè)查詢(沒(méi)有FOR UPDATE/SHARE子句)只能看到查詢開(kāi)始之前已經(jīng)被提交的數(shù)據(jù), 而無(wú)法看到未提交的數(shù)據(jù)或在查詢執(zhí)行期間其它事務(wù)提交的數(shù)據(jù)。實(shí)際上,SELECT查詢看到的是一個(gè)在查詢開(kāi)始運(yùn)行的瞬間該數(shù)據(jù)庫(kù)的一個(gè)快照。不過(guò)SELECT可以看見(jiàn)在它自身事務(wù)中之前執(zhí)行的更新的效果,即使它們還沒(méi)有被提交。還要注意的是,即使在同一個(gè)事務(wù)里兩個(gè)相鄰的SELECT命令可能看到不同的數(shù)據(jù), 因?yàn)槠渌聞?wù)可能會(huì)在第一個(gè)SELECT開(kāi)始和第二個(gè)SELECT開(kāi)始之間提交。
讀已提交模式中,每個(gè)命令都是從一個(gè)新的快照開(kāi)始的,而這個(gè)快照包含在該時(shí)刻已提交的事務(wù), 因此同一事務(wù)中的后續(xù)命令將看到任何已提交的并行事務(wù)的效果。
可重復(fù)讀隔離級(jí)別
可重復(fù)讀隔離級(jí)別只看到在事務(wù)開(kāi)始之前被提交的數(shù)據(jù);它從來(lái)看不到未提交的數(shù)據(jù)或者并行事務(wù)在本事務(wù)執(zhí)行期間提交的修改(不過(guò),查詢能夠看見(jiàn)在它的事務(wù)中之前執(zhí)行的更新,即使它們還沒(méi)有被提交)。
這個(gè)級(jí)別與讀已提交不同之處在于,一個(gè)可重復(fù)讀事務(wù)中的查詢可以看見(jiàn)在事務(wù)中第一個(gè)非事務(wù)控制語(yǔ)句開(kāi)始時(shí)的一個(gè)快照,而不是事務(wù)中當(dāng)前語(yǔ)句開(kāi)始時(shí)的快照。因此,在一個(gè)單一事務(wù)中的后續(xù)SELECT命令看到的是相同的數(shù)據(jù),即它們看不到其他事務(wù)在本事務(wù)啟動(dòng)后提交的修改。
使用這個(gè)級(jí)別的應(yīng)用必須準(zhǔn)備好由于序列化失敗而重試事務(wù)。
注意只有更新事務(wù)可能需要被重試;只讀事務(wù)將永遠(yuǎn)不會(huì)有序列化沖突。
可序列化隔離級(jí)別
可序列化隔離級(jí)別提供了最嚴(yán)格的事務(wù)隔離。這個(gè)級(jí)別為所有已提交事務(wù)模擬序列事務(wù)執(zhí)行;就好像事務(wù)被按照序列一個(gè)接著另一個(gè)被執(zhí)行,而不是并行地被執(zhí)行。但是,和可重復(fù)讀級(jí)別相似,使用這個(gè)級(jí)別的應(yīng)用必須準(zhǔn)備好因?yàn)樾蛄谢《卦囀聞?wù)。事實(shí)上,這個(gè)給力級(jí)別完全像可重復(fù)讀一樣地工作,除了它會(huì)監(jiān)視一些條件,這些條件可能導(dǎo)致一個(gè)可序列化事務(wù)的并發(fā)集合的執(zhí)行產(chǎn)生的行為與這些事務(wù)所有可能的序列化(一次一個(gè))執(zhí)行不一致。這種監(jiān)控不會(huì)引入超出可重復(fù)讀之外的阻塞,但是監(jiān)控會(huì)產(chǎn)生一些負(fù)荷,并且對(duì)那些可能導(dǎo)致序列化異常的條件的檢測(cè)將觸發(fā)一次序列化失敗。