一组表上的同时更新和删除是否会导致使用 AccessExclusiveLock?

The*_*ind 6 postgresql deadlock locking postgresql-9.3

我正在使用 Postgres 9.3。

我有 2 个表 :authn_sessioncustomer. 每个都authn_session属于 a customer(因此有 acustomer_id作为列,这是客户的 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); 
Run Code Online (Sandbox Code Playgroud)

发送: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';
Run Code Online (Sandbox Code Playgroud)

现在,当我使用下面提到的查询查看锁时,我对某一行感兴趣:

locktype | relation     |mode                |tid| vtid| pid |  granted
tuple    | authn_session|AccessExclusiveLock |   | 11/5| 47894| TRUE
Run Code Online (Sandbox Code Playgroud)

询问 :

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();
Run Code Online (Sandbox Code Playgroud)

现在,根据postgres 文档AccessExclusiveLocks 仅在以下情况下授予:

由 ALTER TABLE、DROP TABLE、TRUNCATE、REINDEX、CLUSTER、VACUUM FULL 和 REFRESH MATERIALIZED VIEW(无 CONCURRENTLY)命令获取。这也是未明确指定模式的 LOCK TABLE 语句的默认锁定模式。

我没有明确地做任何这些事情。那么为什么我的第二个进程(运行第二个事务 - 我检查了它在 DB 中的值)获得 AccessExclusiveLock ?为什么 pg_activities_blocked 视图说第二个进程(Delete)被第一个(UPDATE)阻塞?

顺便说一句,同时运行这两个查询的结果(一次来自每个查询的一个语句)会导致死锁。我是否遗漏了可能导致第二个进程在元组上获得 AccessExclusiveLock 的任何内容?

And*_*y M 8

您引用的是手册的错误部分。该段落来自表级锁部分。您感兴趣的锁类型指定为tuple。这意味着您需要参考手册的 Row-level Locks 部分以了解何时获得了这种锁。

在行级锁开头它说(保留原始重点):

除了表级锁,还有行级锁,可以是排他锁或共享锁。更新或删除特定行时,会自动获取对特定行的排他行级锁。锁一直保持到事务提交或回滚,就像表级锁一样。行级锁不影响数据查询;他们只阻止作者到同一行

因此,锁可以由 Tx 1 或 Tx 2 获取,因为一个是更新行,另一个是删除行。

此外,正如ypercube所指出的那样??在注释中,您的更新语句不受过滤器的限制,因此每个语句都在整个表上运行。当与删除并行运行时,即使是过滤的删除,这样的更新自然会导致获取排他锁的冲突。