pgsql中的事務隔離級別
前言
最近在學習pgsql里面的鎖,但是忽然發現對於事物的隔離有點模糊,不能很好的進行知識的串聯。那么就來認真總結下吧。
事物隔離級別
這是官方文檔的描述
SQL標准定義了四種隔離級別。最嚴格的是可序列化,在標准中用了一整段來定義它,其中說到一組可序列化事務的任意並發執行被保證效果和以某種順序一個一個執行這些事務一樣。其他三種級別使用並發事務之間交互產生的現象來定義,每一個級別中都要求必須不出現一種現象。注意由於可序列化的定義,在該級別上這些現象都不可能發生(這並不令人驚訝--如果事務的效果與每個時刻只運行一個的相同,你怎么可能看見由於交互產生的現象?)。
四種事務隔離級別分別是:
讀未提交
讀已提交
可重復讀
可序列化
在各個級別上被禁止出現的現象是
臟讀
一個事物讀取了另一個並行未提交事物寫入的數據。
不可重復讀
一個事物重新讀取之前的數據,發現這個數據已經被另一個事物(在初讀之后提交)修改。
幻讀
一個事物重新執行了一個返回符合條件的行集合的查詢,發現滿足條件的行集合因為另一個最近提交的事物發生了改變。
序列化異常
成功提交一組事物的結果與這些事物所有可能串行執行結果不一致。
在PostgreSQL中,你可以請求四種標准事務隔離級別中的任意一種,但是內部只實現了三種不同的隔離級別,即 PostgreSQL 的讀未提交模式的行為和讀已提交相同。這是因為把標准隔離級別映射到 PostgreSQL 的多版本並發控制架構的唯一合理的方法。
讀已提交隔離級別
讀已提交是pgsql中默認的隔離級別。當一個事務使用這個隔離級別時,一個查詢(沒有FOR UPDATE/SHARE子句)只能看到查詢開始之前已經
被提交的數據,而無法看到未提交的數據或在查詢執行期間其他事物提交的數據。
在不同的事務之間:SELECT查詢看到的是一個在查詢開始運行的瞬間該數據庫的一個快照,當一個事務a對數據進行了修改,a事務還沒有提交的時候另一個事務b查詢到的數據就是,事務a未修改之前的數據,也就是查詢開始之前的瞬間,數據庫的一個快照。
在同一個事務之間:SELECT可以看見在它自身事務中之前執行的更新的效果,即使它們還沒有被提交。也就是更新完成之后的數據,是馬上可以被查詢到的,這就造成了,在同一個事務之間先后查詢的結果可能不一樣,當更新操作在兩個查詢之間進行,后面的查詢就是更新后的數據了。
UPDATE、DELETE、SELECT FOR UPDATE和SELECT FOR SHARE命令在搜索目標行時的行為和SELECT一樣: 它們將只找到在命令開始時已經被提交的行。 不過,在被找到時,這樣的目標行可能已經被其它並發事務更新(或刪除或鎖住)。在這種情況下, 即將進行的更新將等待第一個更新事務提交或者回滾(如果它還在進行中)。 如果第一個更新事務回滾,那么它的作用將被忽略並且第二個事務可以繼續更新最初發現的行。 如果第一個更新事務提交,若該行被第一個更新者刪除,則第二個更新事務將忽略該行,否則第二個更新者將試圖在該行的已被更新的版本上應用它的操作。該命令的搜索條件(WHERE子句)將被重新計算來看該行被更新的版本是否仍然符合搜索條件。如果符合,則第二個更新者使用該行的已更新版本繼續其操作。在SELECT FOR UPDATE和SELECT FOR SHARE的情況下,這意味着把該行的已更新版本鎖住並返回給客戶端。
可重復讀隔離級別
可重復讀隔離級別只能看到事物之前提交的數據;它從來看不到未提交的數據或者並行
事物在本事務執行期間提交的修改。(不過,查詢能夠看見在它的事務中之前執行的更新,即使它們還沒有被提交)。
這個級別與讀已提交不同之處在於,一個可重復讀事務中的查詢可以看見在事務中第一個非事務控制語句開始時的一個快照,而不是事務中當前語句開始時的快照。因此,在一個單一事務中的后續SELECT命令看到的是相同的數據,即它們看不到其他事務在本事務啟動后提交的修改。
UPDATE、DELETE、SELECT FOR UPDATE和SELECT FOR SHARE命令在搜索目標行時的行為和SELECT一樣: 它們將只找到在事務開始時已經被提交的行。 不過,在被找到時,這樣的目標行可能已經被其它並發事務更新(或刪除或鎖住)。在這種情況下, 可重復讀事務將等待第一個更新事務提交或者回滾(如果它還在進行中)。 如果第一個更新事務回滾,那么它的作用將被忽略並且可重復讀事務可以繼續更新最初發現的行。 但是如果第一個更新事務提交(並且實際更新或刪除該行,而不是只鎖住它),則可重復讀事務將回滾並帶有如下消息
ERROR: could not serialize access due to concurrent update
因為一個可重復讀事務無法修改或者鎖住被其他在可重復讀事務開始之后的事務改變的行。
可序列化隔離級別
可序列化隔離級別提供了最嚴格的事務隔離。這個級別為所有已提交事務模擬序列事務執行;就好像事務被按照序列一個接着另一個被執行,而不是並行地被執行。但是,和可重復讀級別相似,使用這個級別的應用必須准備好因為序列化失敗而重試事務。事實上,這個隔離級別完全像可重復讀一樣地工作,除了它會監視一些條件,這些條件可能導致一個可序列化事務的並發集合的執行產生的行為與這些事務所有可能的序列化(一次一個)執行不一致。這種監控不會引入超出可重復讀之外的阻塞,但是監控會產生一些負荷,並且對那些可能導致序列化異常的條件的檢測將觸發一次序列化失敗。
摘錄
【PostgreSQL 11.2 手冊】http://postgres.cn/docs/11