我有几个查询的交易。首先,选择FOR UPDATE
带锁的行:
SELECT f.source_id FROM files AS f WHERE
f.component_id = $1 AND
f.archived_at IS NULL
FOR UPDATE
接下来是更新查询:
UPDATE files AS f SET archived_at = NOW()
WHERE
hw_component_id = $1 AND
f.source_id = ANY($2::text[])
然后有一个插入:
INSERT INTO files AS f (
source_id,
...
)
VALUES (..)
ON CONFLICT (component_id, source_id) DO UPDATE
SET archived_at = null,
is_valid = excluded.is_valid
我有两个应用程序实例,有时我会在 PostgreSQL 日志中看到死锁错误:
ERROR: deadlock detected
DETAIL: Process 3992939 waits for ShareLock on transaction 230221362; blocked by process 4108096.
Process 4108096 waits for ShareLock on transaction 230221365; blocked by process 3992939.
Process 3992939: SELECT f.source_id FROM files AS f WHERE f.component_id = $1 AND f.archived_at IS NULL FOR UPDATE
Process 4108096: INSERT INTO files AS f (source_id, ...) VALUES (..) ON CONFLICT (component_id, source_id) DO UPDATE SET archived_at = null, is_valid = excluded.is_valid
CONTEXT: while locking tuple (41116,185) in relation \"files\"
我认为它可能是由ON CONFLICT DO UPDATE
语句引起的,该语句可能会更新先前未锁定的行SELECT FOR UPDATE
但是我不明白SELECT ... FOR UPDATE
如果它是事务中的第一个查询,查询如何导致死锁。在它之前没有查询。语句可以SELECT ... FOR UPDATE
锁定几行然后等待条件中的其他行被解锁吗?