一組表的同時更新和刪除會導致 AccessExclusiveLock 被佔用嗎?
我正在使用 Postgres 9.3。
我有 2 張桌子:
authn_session
和customer
。Everyauthn_session
屬於 acustomer
(因此具有 acustomer_id
作為列,它是 customer’s 的 FKid
)。注意:這些表包含對其他表和索引的附加 FK 引用。
現在,我開始了 2 個不同的事務,它們按照下面提到的順序執行以下操作:
發送:1
BEGIN; UPDATE customer SET customer__created_by = (case when customer__created_by = 1 then 5 else customer__created_by end), customer__modified_by = (case when customer__modified_by = 1 then 5 else customer__modified_by end); UPDATE authn_session SET authn_session__created_by = (case when authn_session__created_by = 1 then 5 else authn_session__created_by end), authn_session__modified_by = (case when authn_session__modified_by = 1 then 5 else authn_session__modified_by end);
發送:2
BEGIN; DELETE FROM authn_session WHERE authn_session__guid IN ('abc3344-ab12-4444-9fdd-f4c5a6f7f210'); DELETE FROM customer WHERE customer__id != 0 AND customer__id = 3 AND customer__name = 'C2' AND customer__domain_name = 'a2.com';
現在,當我使用下面提到的查詢查看鎖時,我感興趣的一個特定行:
locktype | relation |mode |tid| vtid| pid | granted tuple | authn_session|AccessExclusiveLock | | 11/5| 47894| TRUE
詢問 :
SELECT locktype, relation::regclass, mode, transactionid AS tid, virtualtransaction AS vtid, pid, granted FROM pg_catalog.pg_locks l LEFT JOIN pg_catalog.pg_database db ON db.oid = l.database WHERE (db.datname = 'mY-db' OR db.datname IS NULL) AND NOT pid = pg_backend_pid();
現在,根據postgres 文件, AccessExclusiveLocks 僅在以下情況下被授予:
由 ALTER TABLE、DROP TABLE、TRUNCATE、REINDEX、CLUSTER、VACUUM FULL 和 REFRESH MATERIALIZED VIEW(無 CONCURRENTLY)命令獲取。這也是未明確指定模式的 LOCK TABLE 語句的預設鎖定模式。
我沒有明確地做任何這些事情。那麼為什麼我的第二個程序(執行第二個事務 - 我檢查了它在 DB 中的值)獲得了 AccessExclusiveLock?為什麼 pg_activities_blocked 視圖說第二個程序(刪除)被第一個(更新)阻止?
順便說一句,同時執行這兩個查詢的結果(一次來自每個查詢的一條語句)會導致死鎖。我是否遺漏了任何可能導致第二個程序在元組上獲得 AccessExclusiveLock 的內容?
您引用了手冊的錯誤部分。這段話來自 Table-level Locks 部分。您感興趣的鎖類型指定為
tuple
。這意味著您需要參考手冊的行級鎖部分,以了解何時獲取這種鎖。在行級鎖的開頭它說(保留原始重點):
除了表級鎖,還有行級鎖,可以是排他鎖,也可以是共享鎖。更新或刪除行時,會自動獲取特定行上的排他行級鎖。鎖一直保持到事務送出或回滾,就像表級鎖一樣。行級鎖不影響數據查詢;他們只阻止同一行的作者。
因此,鎖可以由 Tx 1 或 Tx 2 獲取,因為一個正在更新行,另一個正在刪除行。
此外,正如ypercubeᵀᴹ在評論中指出的那樣,您的更新語句不受過濾器的限制,因此每個語句都在整個表上執行。當與刪除(甚至是過濾)並行執行時,這樣的更新自然會導致獲取排他鎖的衝突。