支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

13.4. 在應用程式層級進行資料一致性檢查 #

由於資料的檢視會隨著每個語句而變動,而且如果發生寫入衝突,即使是單一語句也可能不會將自己限制在語句的快照中,因此很難使用「讀取已提交」交易來強制執行關於資料完整性的業務規則。

雖然「可重複讀取」交易在其整個執行過程中都具有穩定的資料檢視,但在使用MVCC快照進行資料一致性檢查時,存在一個微妙的問題,其中涉及到一種稱為讀取/寫入衝突的東西。如果一個交易寫入資料,而另一個並行交易嘗試讀取相同的資料(無論是在寫入之前還是之後),它都無法看到另一個交易的工作。然後,讀取者似乎是先執行的,而不管哪個先啟動或哪個先提交。如果僅此而已,就沒有問題,但如果讀取者也寫入由並行交易讀取的資料,則現在有一個交易似乎是在先前提及的任一交易之前執行的。如果實際上看起來是最後執行的交易首先提交,則很容易在交易執行順序的圖表中出現循環。當出現這樣的循環時,如果沒有任何幫助,完整性檢查將無法正常工作。

第 13.2.3 節中所述,「可序列化」交易只是「可重複讀取」交易,它增加了對危險的讀取/寫入衝突模式的非封鎖監控。當檢測到可能導致執行順序中出現循環的模式時,會回滾涉及的其中一個交易以打破循環。

13.4.1. 使用可序列化交易強制執行一致性 #

如果「可序列化」交易隔離層級用於所有寫入和所有需要一致資料檢視的讀取,則無需其他努力即可確保一致性。來自其他環境且編寫為使用可序列化交易以確保一致性的軟體,在這方面應在 PostgreSQL直接運作

使用此技術時,如果應用程式軟體透過一個框架自動重試因序列化失敗而回滾的交易,則可以避免為應用程式程式設計師帶來不必要的負擔。將 default_transaction_isolation 設定為 serializable 可能是一個好主意。明智的做法是採取一些行動,以確保不會透過觸發器中的交易隔離層級檢查來無意或顛覆完整性檢查地使用任何其他交易隔離層級。

有關效能建議,請參閱第 13.2.3 節

警告:可序列化交易和資料複寫

使用可序列化交易提供此等級的完整性保護,目前尚未擴展到熱備援模式(第 26.4 節)或邏輯複本。因此,使用熱備援或邏輯複寫的人員可能希望在主要資料庫上使用可重複讀取 (Repeatable Read) 和明確鎖定。

13.4.2. 使用明確阻擋鎖強制一致性 #

當非序列化的寫入是可能發生的情況下,為了確保目前列的有效性並防止其同時被更新,必須使用 SELECT FOR UPDATESELECT FOR SHARE 或適當的 LOCK TABLE 陳述式。(SELECT FOR UPDATESELECT FOR SHARE 僅鎖定傳回的列以防止同時更新,而 LOCK TABLE 鎖定整個資料表。)從其他環境將應用程式移植到 PostgreSQL 時,應考慮到這一點。

另外,從其他環境轉換過來的人員要注意的是,SELECT FOR UPDATE 並不保證同時進行的交易不會更新或刪除選定的列。 要在 PostgreSQL 中執行此操作,您實際上必須更新該列,即使不需要變更任何值。SELECT FOR UPDATE 暫時阻止其他交易取得相同的鎖定或執行會影響鎖定列的 UPDATEDELETE,但是一旦持有此鎖定的交易提交或回滾,則除非在持有鎖定時實際執行了列的 UPDATE,否則被阻止的交易將繼續執行衝突的操作。

在非序列化的情況下,全域有效性檢查需要額外的思考MVCC。例如,銀行應用程式可能希望檢查一個資料表中所有貸項的總和是否等於另一個資料表中借項的總和,而這兩個資料表都在積極更新中。 比較兩個連續 SELECT sum(...) 命令的結果在讀取已提交模式 (Read Committed) 下無法可靠運作,因為第二個查詢很可能包含第一個查詢未計算在內的交易結果。 在單個可重複讀取 (Repeatable Read) 交易中執行這兩個總和運算將僅準確顯示在可重複讀取交易開始之前提交的交易的影響 — 但是人們可能會合理地懷疑,在交付答案時它是否仍然相關。 如果可重複讀取交易本身在嘗試進行一致性檢查之前應用了一些變更,則檢查的用處甚至變得更值得商榷,因為現在它包含了一些但並非所有交易開始後的變更。 在這種情況下,謹慎的人可能希望鎖定檢查所需的所有資料表,以便獲得對當前實際情況的無可爭辯的理解。 SHARE 模式(或更高)鎖定保證鎖定資料表中沒有未提交的變更,除了當前交易的變更之外。

另請注意,如果依賴明確鎖定來防止同時變更,則應使用讀取已提交模式 (Read Committed),或者在可重複讀取模式 (Repeatable Read) 下,在執行查詢之前務必取得鎖定。 可重複讀取交易取得的鎖定可保證沒有其他修改資料表的交易仍在執行,但是如果交易看到的快照早於取得鎖定,則它可能早於資料表中的某些現在已提交的變更。 可重複讀取交易的快照實際上在其第一個查詢或資料修改命令(SELECTINSERTUPDATEDELETEMERGE)開始時凍結,因此可以在快照凍結之前明確取得鎖定。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。