Postgresql

一組表的同時更新和刪除會導致 AccessExclusiveLock 被佔用嗎?

  • December 13, 2017

我正在使用 Postgres 9.3。

我有 2 張桌子:authn_sessioncustomer。Everyauthn_session屬於 a customer(因此具有 acustomer_id作為列,它是 customer’s 的 FK id)。

注意:這些表包含對其他表和索引的附加 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ᵀᴹ在評論中指出的那樣,您的更新語句不受過濾器的限制,因此每個語句都在整個表上執行。當與刪除(甚至是過濾)並行執行時,這樣的更新自然會導致獲取排他鎖的衝突。

引用自:https://dba.stackexchange.com/questions/192644