由於讀已提交事務中資料檢視在每個語句之間都在變化,即使是單個語句在發生寫衝突時也可能無法限制在語句的快照範圍內,因此使用讀已提交事務來強制執行關於資料完整性的業務規則非常困難。
雖然可重複讀事務在整個執行過程中都有穩定的資料檢視,但在使用MVCC快照進行資料一致性檢查時,存在一個微妙的問題,涉及所謂的 讀/寫衝突。如果一個事務寫入資料,而另一個併發事務嘗試讀取相同的資料(無論是在寫入之前還是之後),它將無法看到另一個事務的工作。無論哪個事務先開始,哪個事務先提交,讀取者都似乎先執行。如果僅止於此,就沒有問題,但如果讀取者還寫入了其他事務正在讀取的資料,那麼現在就會有一個事務,它似乎比前面提到的任何一個事務都先執行。如果最後一個執行的事務實際先提交,那麼在事務的執行順序圖譜中很容易出現一個迴圈。當出現這樣的迴圈時,一致性檢查在沒有幫助的情況下將無法正確工作。
正如 第 13.2.3 節 所述,可序列化事務只是可重複讀事務,它增加了對危險的讀/寫衝突模式的非阻塞監控。當檢測到可能導致執行順序出現迴圈的模式時,其中一個涉及的事務將被回滾以打破迴圈。
如果為所有寫入以及所有需要一致資料檢視的讀取使用可序列化事務隔離級別,則無需其他工作即可確保一致性。從其他環境移植到 PostgreSQL 的、為了保證一致性而編寫成使用可序列化事務的軟體,在這方面應該“開箱即用”。
使用此技術時,如果應用程式軟體透過一個自動重試因序列化失敗而回滾的事務的框架,將避免給應用程式程式設計師帶來不必要的負擔。將 default_transaction_isolation
設定為 serializable
可能是一個好主意。另外,透過觸發器檢查事務隔離級別,採取一些措施確保不會意外或為了規避一致性檢查而使用其他事務隔離級別,也是明智之舉。
有關效能建議,請參閱 第 13.2.3 節。
使用可序列化事務進行的此級別的完整性保護尚未擴充套件到熱備模式(第 26.4 節)或邏輯複製。因此,那些使用熱備或邏輯複製的使用者可能希望在主伺服器上使用可重複讀和顯式鎖定。
當可能發生非可序列化寫入時,要確保行的當前有效性並保護其免受併發更新的影響,必須使用 SELECT FOR UPDATE
、SELECT FOR SHARE
或適當的 LOCK TABLE
語句。(SELECT FOR UPDATE
和 SELECT FOR SHARE
只鎖定返回的行以防止併發更新,而 LOCK TABLE
則鎖定整個表。)在將應用程式從其他環境移植到 PostgreSQL 時,應將此考慮在內。
對於從其他環境轉換的使用者來說,還需要注意的是,SELECT FOR UPDATE
並不能確保併發事務不會更新或刪除選定的行。要在 PostgreSQL 中做到這一點,即使不需要更改任何值,也必須實際更新該行。SELECT FOR UPDATE
暫時阻塞其他事務獲取相同鎖或執行會影響被鎖定行的 UPDATE
或 DELETE
,但一旦持有此鎖的事務提交或回滾,被阻塞的事務將繼續執行衝突的操作,除非在持有鎖期間實際執行了對該行的 UPDATE
。
全域性有效性檢查在非可序列化模式下需要額外的考慮MVCC。例如,一個銀行應用程式可能希望檢查一個表中的所有貸項總和是否等於另一個表中的所有借項總和,當兩個表都在積極更新時。在讀已提交模式下,比較兩次連續 SELECT sum(...)
命令的結果是不可靠的,因為第二個查詢很可能包含第一個查詢未計入的事務結果。在單個可重複讀事務中進行兩次求和將只准確反映在可重複讀事務開始之前已提交的事務的影響——但人們可能會合理地懷疑,當結果交付時,這個答案是否仍然相關。如果可重複讀事務在嘗試進行一致性檢查之前本身應用了一些更改,那麼檢查的有用性就更值得商榷了,因為它現在包含了一些但並非所有事務開始後的更改。在這些情況下,一個謹慎的人可能會希望鎖定檢查所需的所有表,以獲得當前現實的無可爭議的畫面。SHARE
模式(或更高)的鎖保證在鎖定表中的未提交更改(除當前事務的更改外)不存在。
另請注意,如果依賴顯式鎖定來防止併發更改,則應使用讀已提交模式,或者在可重複讀模式下小心地在執行查詢之前獲取鎖。由可重複讀事務獲得的鎖保證沒有其他修改表的事務仍在執行,但如果事務看到快照早於獲取鎖的時間,那麼它可能早於表中某些已提交的更改。可重複讀事務的快照實際上是在其第一個查詢或資料修改命令(SELECT
、INSERT
、UPDATE
、DELETE
或 MERGE
)開始時凍結的,因此有可能在快照凍結之前顯式獲取鎖。
如果您在文件中發現任何不正確、與您對特定功能的使用經驗不符或需要進一步澄清的內容,請使用 此表格 報告文件問題。