日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

事務隔離

SQL標準定義了四種隔離級別。最嚴格的是可序列化,在標準中用了一整段來定義它,其中說到一組可序列化事務的任意并發執行被保證效果和以某種順序一個一個執行這些事務一樣。

其他三種級別使用并發事務之間交互產生的現象來定義,每一個級別中都要求必須不出現一種現象。注意由于可序列化的定義,在該級別上這些現象都不可能發生(這并不令人驚訝--如果事務的效果與每個時刻只運行一個的相同,你怎么可能看見由于交互產生的現象?)。在各個級別上被禁止出現的現象是:

  • 臟讀 一個事務讀取了另一個并行未提交事務寫入的數據。

  • 不可重復讀 一個事務重新讀取之前讀取過的數據,發現該數據已經被另一個事務(在初始讀之后提交)修改。

  • 幻讀 一個事務重新執行一個返回符合一個搜索條件的行集合的查詢, 發現滿足條件的行集合因為另一個最近提交的事務而發生了改變。

  • 序列化異常 成功提交一組事務的結果與這些事務所有可能的串行執行結果都不一致。

SQL 標準和 PostgreSQL 實現的事務隔離級別在表 1 中描述。

表 1. 事務隔離級別

隔離級別

臟讀

不可重復讀

幻讀

序列化異常

讀未提交

允許,但不在 PG 中

可能

可能

可能

讀已提交

不可能

可能

可能

可能

可重復讀

不可能

不可能

允許,但不在 PG 中

可能

可序列化

不可能

不可能

不可能

不可能

在本數據庫中,你可以請求四種標準事務隔離級別中的任意一種,但是內部只實現了三種不同的隔離級別,即 PostgreSQL 的讀未提交模式的行為和讀已提交相同。這是因為把標準隔離級別映射到 PostgreSQL 的多版本并發控制架構的唯一合理的方法。該表格也顯示 PostgreSQL 的可重復讀實現不允許幻讀。而 SQL 標準允許更嚴格的行為:四種隔離級別只定義了哪種現像不能發生,但是沒有定義哪種現像必須發生。可用的隔離級別的行為在下面的小節中詳細描述。要設置一個事務的事務隔離級別,使用SET TRANSACTION命令。

重要

某些本數據庫數據類型和函數關于事務的行為有特殊的規則。特別是,對一個序列的修改(以及用serial聲明的一列的計數器)是立刻對所有其他事務可見的,并且在作出該修改的事務中斷時也不會被回滾。

讀已提交隔離級別

讀已提交是本數據庫中的默認隔離級別。當一個事務使用這個隔離級別運行時, 一個查詢(沒有FOR UPDATE/SHARE子句)只能看到查詢開始之前已經被提交的數據,而無法看到未提交的數據或在查詢執行期間其它事務提交的數據。實際上,SELECT查詢看到的是一個在查詢開始運行的瞬間該數據庫的一個快照。不過SELECT可以看見在它自身事務中之前執行的更新的效果,即使它們還沒有被提交。還要注意的是,即使在同一個事務里兩個相鄰的SELECT命令可能看到不同的數據,因為其它事務可能會在第一個SELECT開始和第二個SELECT開始之間提交。

UPDATE、DELETE、SELECT FOR UPDATESELECT FOR SHARE命令在搜索目標行時的行為和SELECT一樣:它們將只找到在命令開始時已經被提交的行。不過,在被找到時,這樣的目標行可能已經被其它并發事務更新(或刪除或鎖?。?。在這種情況下,即將進行的更新將等待第一個更新事務提交或者回滾(如果它還在進行中)。如果第一個更新事務回滾,那么它的作用將被忽略,并且第二個事務可以繼續更新最初發現的行。如果第一個更新事務提交,若該行被第一個更新者刪除,則第二個更新事務將忽略該行,否則第二個更新者將試圖在該行的已被更新的版本上應用它的操作。該命令的搜索條件(WHERE子句)將被重新計算,以確定該行被更新的版本是否仍然符合搜索條件。如果符合,則第二個更新者使用該行的已更新版本繼續其操作。在SELECT FOR UPDATESELECT FOR SHARE的情況下,這意味著把該行的已更新版本鎖住并返回給客戶端。帶有ON CONFLICT DO UPDATE子句的INSERT行為類似。在讀已提交模式下,要插入的每一行將被插入或者更新。除非有不相關的錯誤出現,這兩種結果之一是肯定會出現的。如果在另一個事務中發生沖突,并且其效果對于INSERT還不可見,則UPDATE子句將會影響那個行,即便那一行對于該命令來說沒有慣常的可見版本。帶有ON CONFLICT DO NOTHING子句的INSERT有可能因為另一個效果對INSERT快照不可見的事務的結果無法讓插入進行下去。再一次,這只是讀已提交模式中的情況。因為上面的規則,正在更新的命令可能會看到一個不一致的快照:它們可以看到并發更新命令在它嘗試更新的相同行上的作用,但是卻看不到那些命令對數據庫里其它行的作用。這樣的行為令讀已提交模式不適合用于涉及復雜搜索條件的命令。不過,它對于更簡單的情況是正確的。例如,考慮用這樣的命令更新銀行余額:

    BEGIN;
    UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 12345;
    UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 7534;
    COMMIT;

如果兩個這樣的事務同時嘗試修改賬號 12345 的余額,那我們很明顯希望第二個事務從賬戶行的已更新版本上開始工作。 因為每個命令只影響一個已經決定了的行,讓它看到行的已更新版本不會導致任何麻煩的不一致性。在讀已提交模式中,更復雜的使用可能產生不符合需要的結果。例如: 考慮一個在數據上操作的DELETE命令,它操作的數據正被另一個命令從它的限制條件中移除或者加入,例如,假定website是一個兩行的表,兩行的website.hits等于910

    BEGIN;
    UPDATE website SET hits = hits + 1;
    -- run from another session:  DELETE FROM website WHERE hits = 10;
    COMMIT;

即便在UPDATE之前有一個website.hits = 10的行,DELETE將不會產生效果。這是因為更新之前的行值9被跳過,并且當UPDATE完成并且DELETE獲得一個鎖,新行值不再是10而是11,這再也不匹配條件了。因為在讀已提交模式中,每個命令都是從一個新的快照開始的,而這個快照包含在該時刻已提交的事務, 因此同一事務中的后續命令將看到任何已提交的并行事務的效果。以上的焦點在于單個命令是否看到數據庫的絕對一致的視圖。讀已提交模式提供的部分事務隔離對于許多應用而言是足夠的,并且這個模式速度快并且使用簡單。 不過,它不是對于所有情況都夠用。做復雜查詢和更新的應用可能需要比讀已提交模式提供的更嚴格一致的數據庫視圖。

可重復讀隔離級別

可重復讀隔離級別只看到在事務開始之前被提交的數據;它從來看不到未提交的數據或者并行事務在本事務執行期間提交的修改(不過,查詢能夠看見在它的事務中之前執行的更新,即使它們還沒有被提交)。這是比 SQL 標準對此隔離級別所要求的更強的保證,并且阻止表 1 中描述的除了序列化異常之外的所有現象。如上面所提到的,這是標準特別允許的,標準只描述了每種隔離級別必須提供的最小保護。這個級別與讀已提交不同之處在于,一個可重復讀事務中的查詢可以看見在事務中第一個非事務控制語句開始時的一個快照,而不是事務中當前語句開始時的快照。因此,在一個單一事務中的后續SELECT命令看到的是相同的數據,即它們看不到其他事務在本事務啟動后提交的修改。使用這個級別的應用必須準備好由于序列化失敗而重試事務。UPDATE、DELETESELECT FOR UPDATESELECT FOR SHARE命令在搜索目標行時的行為和SELECT一樣: 它們將只找到在事務開始時已經被提交的行。 不過,在被找到時,這樣的目標行可能已經被其它并發事務更新(或刪除或鎖?。?。在這種情況下, 可重復讀事務將等待第一個更新事務提交或者回滾(如果它還在進行中)。 如果第一個更新事務回滾,那么它的作用將被忽略并且可重復讀事務可以繼續更新最初發現的行。 但是如果第一個更新事務提交(并且實際更新或刪除該行,而不是只鎖住它),則可重復讀事務將回滾并帶有如下消息

    ERROR:  could not serialize access due to concurrent update

因為一個可重復讀事務無法修改或者鎖住被其他在可重復讀事務開始之后的事務改變的行。當一個應用接收到這個錯誤消息,它應該中斷當前事務并且從開頭重試整個事務。在第二次執行中,該事務將見到作為其初始數據庫視圖一部分的之前提交的改變,這樣在使用行的新版本作為新事務更新的起點時就不會有邏輯沖突。注意只有更新事務可能需要被重試;只讀事務將永遠不會有序列化沖突??芍貜妥x模式提供了一種嚴格的保證,在其中每一個事務看到數據庫的一個完全穩定的視圖。不過,這個視圖并不需要總是和同一級別上并發事務的某些序列化(一次一個)執行保持一致。例如,即使這個級別上的一個只讀事務可能看到一個控制記錄被更新,這顯示一個批處理已經被完成但是不能看見作為該批處理的邏輯組成部分的一個細節記錄,因為它讀取空值記錄的一個較早的版本。如果不小心地使用顯式鎖來阻塞沖突事務,嘗試用運行在這個隔離級別的事務來強制業務規則不太可能正確地工作??芍貜妥x隔離級別是使用學術數據庫文獻和一些其他數據庫產品中稱為Snapshot Isolation的已知的技術來實現的。 與使用傳統鎖技術并降低并發性的系統相比,可以觀察到行為和性能方面的差異。 一些其他系統甚至可以提供可重復讀取和快照隔離作為具有不同行為的不同隔離級別。 直到 SQL 標準開發出來之后,數據庫研究人員才正式確定區分這兩種技術的允許現象,并且超出了本手冊的范圍。

說明

一個對于可序列化事務隔離級別的請求會提供和這里描述的完全一樣的行為。為了保持可序列化行為,現在應該請求可重復讀。

可序列化隔離級別

可序列化隔離級別提供了最嚴格的事務隔離。這個級別為所有已提交事務模擬序列事務執行;就好像事務被按照序列一個接著另一個被執行,而不是并行地被執行。但是,和可重復讀級別相似,使用這個級別的應用必須準備好因為序列化失敗而重試事務。事實上,這個隔離級別完全像可重復讀一樣地工作,除了它會監視一些條件,這些條件可能導致一個可序列化事務的并發集合的執行產生的行為與這些事務所有可能的序列化(一次一個)執行不一致。這種監控不會引入超出可重復讀之外的阻塞,但是監控會產生一些負荷,并且對那些可能導致序列化異常的條件的檢測將觸發一次序列化失敗。例如,考慮一個表mytab,它初始時包含:

     class | value
    -------+-------
         1 |    10
         1 |    20
         2 |   100
         2 |   200

假設可序列化事務 A 計算:

    SELECT SUM(value) FROM mytab WHERE class = 1;

并且接著把結果(3)作為一個新行的value插入,新行的class`` = 2。同時,可序列化事務 B 計算:

    SELECT SUM(value) FROM mytab WHERE class = 2;

并得到結果 300,它會將其與class`` = 1插入到一個新行中。然后兩個事務都嘗試提交。如果其中一個事務運行在可重復讀隔離級別,兩者都被允許提交;但是由于沒有執行的序列化順序能在結果上一致,使用可序列化事務將允許一個事務提交并且將回滾另一個并伴有這個消息:

    ERROR:  could not serialize access due to read/write dependencies among transactions

這是因為,如果 A 在 B 之前執行,B 將計算得到合計值 330 而不是 300,而且相似地另一種順序將導致 A 計算出一個不同的合計值。當依賴可序列化事務來阻止異常時,重要的一點是任何從一個持久化用戶表讀出數據都不被認為是有效的,直到讀它的事務已經成功提交為止。即便是對只讀事務也是如此,除了在一個可推遲的只讀事務中讀取的數據是讀出以后立刻有效的,因為這樣的一個事務在開始讀取任何數據之前會等待,直到它能獲得一個快照保證來避免這種問題為止。在所有其他情況下,應用不能依靠在一個后來被中斷的事務中讀取的結果;相反,它們應當重試事務直到它成功。要保證真正的可序列化,本數據庫使用了謂詞鎖,這意味著它會保持鎖,這些鎖讓它能夠判斷在它先運行的情況下,什么時候一個寫操作會對一個并發事務中之前讀取的結果產生影響。在本數據庫中,這些鎖并不導致任何阻塞,并且因此會導致一個死鎖。它們被用來標識和標志并發可序列化事務之間的依賴性,這些事務的組合可能導致序列化異常。相反,一個想要保證數據一致性的讀已提交或可重復讀事務可能需要拿走一個在整個表上的鎖,這可能阻塞其他嘗試使用該表的用戶,或者它可能會使用不僅會阻塞其他事務還會導致磁盤訪問的SELECT FOR UPDATESELECT FOR SHARE。像大部分其他數據庫系統,本數據庫中的謂詞鎖基于被一個事務真正訪問的數據。這些謂詞鎖將顯示在lockspg系統視圖中,它們的modeSIReadLock。這種在一個查詢執行期間獲得的特別的鎖將依賴于該查詢所使用的計劃,并且在事務過程中多個細粒度鎖(如元組鎖)可能和少量粗粒度鎖(如頁面鎖)相結合來防止耗盡用于跟蹤鎖的內存。如果一個READ ONLY事務檢測到不會有導致序列化異常的沖突發生,它可以在完成前釋放其 SIRead 鎖。事實上,READ ONLY事務將常??梢栽趩訒r確立這一事實并避免拿到任何謂詞鎖。如果你顯式地請求一個SERIALIZABLE READ ONLY DEFERRABLE事務,它將阻塞直到它能夠確立這一事實(這是唯一_一種可序列化事務阻塞但可重復讀事務不阻塞的情況)。在另一方面,SIRead 鎖常常需要被保持到事務提交之后,直到重疊的讀寫事務完成。堅持使用可序列化事務可以簡化開發。成功提交的并發可序列化事務的任意集合將得到和一次運行一個相同效果的這種保證意味著,如果你能證明一個單一事務在獨自運行時能做正確的事情,則你可以相信它在任何混合的可序列化事務中也能做正確的事情,即使它不知道那些其他事務做了些什么,否則它將不會成功提交。重要的是使用這種技術的環境有一種普遍的方法來處理序列化失?。偸菚祷匾粋€ SQLSTATE 值 '40001'),因為它將很難準確地預計哪些事務可能為讀/寫依賴性做貢獻并且需要被回滾來阻止序列化異常。讀/寫依賴性的監控會產生開銷,如重啟被序列化失敗中止的事務,但是作為在該開銷和顯式鎖及SELECT FOR UPDATESELECT FOR SHARE導致的阻塞之間的一種平衡,可序列化事務是在某些環境中最好性能的選擇。雖然本數據庫的可序列化事務隔離級別只允許并發事務在能夠證明有一種串行執行能夠產生相同效果的前提下提交,但它卻不能總是阻止在真正的串行執行中不會發生的錯誤產生。尤其是可能會看到由于可序列化事務重疊執行導致的唯一約束被違背的情況,這些情況即便在嘗試插入鍵之前就顯式地檢查過該鍵不存在也會發生。避免這種問題的方法是,確保所有插入可能會沖突的鍵的可序列化事務首先顯式地檢查它們能不能那樣做。例如,試想一個要求用戶輸入新鍵的應用,它會通過嘗試查詢用戶給出的鍵來檢查鍵是否已經存在,或者是通過選取現有最大的鍵并且加一來產生一個新鍵。如果某些可序列化事務不遵循這種協議而直接插入新鍵,則也可能會報告唯一約束被違背,即便在并發事務串行執行的情況下不會發生唯一約束被違背也是如此。當依賴可序列化事務進行并發控制時,為了最佳性能應該考慮一下問題:

  • 在可能時聲明事務為READ ONLY。

  • 控制活動連接的數量,如果需要使用一個連接池。這總是一個重要的性能考慮,但是在一個使用可序列化事務的繁忙系統中這尤為重要。

  • 只在一個單一事務中放完整性目的所需要的東西。

  • 不要讓連接不必要地“閑置在事務中”。配置參數 idle_in_transaction_session_timeout 可以被用來自動斷開拖延會話的連接。

  • 在那些由于使用可序列化事務自動提供的保護的地方消除不再需要的顯式鎖、SELECT FOR UPDATESELECT FOR SHARE。

  • 當系統因為謂詞鎖表內存短缺而被強制結合多個頁面級謂詞鎖為一個單一的關系級謂詞鎖時,序列化失敗的比例可能會上升。你可以通過增加 max_pred_locks_per_transaction、max_pred_locks_per_relation 和 max_pred_locks_per_page 來避免這種情況。

  • 一次順序掃描將總是需要一個關系級謂詞鎖。這可能導致序列化失敗的比例上升。通過縮減 random_page_cost 和/或增加 cpu_tuple_cost 來鼓勵使用索引掃描將有助于此。一定要在事務回滾和重啟數目的任何減少與查詢執行時間的任何全面改變之間進行權衡。

可序列化隔離級別是使用學術數據庫文獻中稱為可序列化快照隔離的技術實現的,通過添加序列化異常事務的檢查的方式構建在快照隔離的基礎之上。 與使用傳統鎖技術的其他系統相比,可以觀察到行為和性能方面的一些差異。