描述隔離等級
PostgreSQL 有三個交易隔離等級,可防止三種類型的並行衝突:中途讀取、不可重複讀取,以及虛設讀取。
並行衝突類型
中途讀取
當某筆交易讀取另一筆交易正在編輯的資料更新版本時,就會發生中途讀取。 不過,此更新從未提交。
例如,交易發生在將帳戶餘額設為少於零的儲蓄帳戶上。 在提交交易之前,會檢查帳戶餘額並回復交易,因為儲蓄帳戶的餘額不允許少於零。 同時,會執行報告以顯示所有儲蓄帳戶的目前餘額。 如果允許中途讀取,則即使從未提交,也會傳回負餘額。
不可重複讀取
如果一筆交易:讀取資料,另一筆交易更新資料,而初始交易再次讀取資料並看到新的更新,則會發生不可重複的讀取。
例如,連線 A 啟動交易,並讀取訂單的每單位成本與單位數,即成本為 10,單位數為 3。 連線 B 接著啟動另一筆交易,並更新相同的訂單,將每單位的成本設定為 12。 在與原始查詢相同的交易中,連接 A 會計算訂單的總成本。 如果允許不可重複的讀取,則連線 A 會傳回每單位成本 10、單位數 3、總成本 36,這顯然不合理。
虛設項目讀取
如果一筆交易:讀取資料,另一筆交易向該資料新增一個新的資料列 (或多個資料列),而且初始交易再次讀取該資料並看到新的更新,則會發生虛設讀取。
例如,連線 A 會啟動交易並計算巴黎當天的發票總數。 巴黎所有 10 家商店共清點了 1,100 張發票。 連線 B 接著啟動另一筆交易,並在巴黎新增一間新的零售商店,並為新店開業當天提供 200 張發票。 在連線 A 交易中,系統現在會計算商店數目,以計算每家商店的發票數目。 連線 A 現在會將 1,100 筆交易除以 11 家商店,而不是執行發票計數查詢時存在的原本 10 家商店。 現在,此計算會傳回錯誤的平均值 100,即使新商店有 200 張發票,而連線 A 交易在其平均計算中並未考慮到這些發票也一樣。
隔離等級
適用於 PostgreSQL 的 Azure 資料庫有三個交易隔離等級:讀取認可、可重複讀取,以及可序列化。 讀取未認可無法在適用於 PostgreSQL 的 Azure 資料庫中使用。
隔離等級會如何影響並行衝突:
隔離等級 | 中途讀取 (Dirty read) | 不可重複讀取 | 虛設讀取 |
---|---|---|---|
讀取未認可* | 可能 | 可能 | 可能 |
讀取認可 | 不可行 | 可能 | 可能 |
可重複讀取 | 不可行 | 不可行 | 可能 |
可序列化 | 不可行 | 不可行 | 不可行 |
* 無法在 PostgreSQL 中使用
讀取認可是適用於 PostgreSQL 之 Azure 資料庫的預設隔離等級。 讀取認可最適合大部分的案例,因為其會在提供良好的效能時防止中途讀取。 可能會出現不可重複的讀取和虛設讀取,但只有當有多個 SELECT 陳述式同時查詢相同的資料時,才會出現這些情況。
可重複的讀取與已提交的讀取不同,因為即使另一筆交易在交易的兩個 SELECT 陳述式執行之間更新了資料列,交易中的多個 SELECT 陳述式也會看到相同的結果。 如果另一筆交易插入新的資料列,這些資料列就不會出現在第二個 SELECT 陳述式的結果中。
可序列化的隔離等級提供最高層級的交易隔離並加以執行,就像不同交易在序列中執行一樣,逐一發生。 可序列化隔離等級的缺點是,如果一筆交易正在執行更新,其他交易可能會阻止它。 可序列化交易必須等到阻止的交易完成為止,這會影響效能。
可序列化交易也無法對其他交易在可序列化交易期間修改的任何資料列進行變更。 若發生此衝突形式,則會傳回錯誤訊息,因此在使用可序列化交易時,請務必在應用程式中內建重試邏輯。
若要更新交易隔離等級,請在交易中使用 TRANSACTION ISOLATION LEVEL 命令。
例如:
BEGIN TRANSACTION
TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM humanresources.department
COMMIT;