我将Postgres 12与autocommit = off
一起使用,并尝试通过使用显式锁定来避免死锁。当我执行时:
ROLLBACK;
SELECT * FROM account WHERE id = 12345 FOR UPDATE;
其中id
是account
的主键。有时我在第二条陈述上陷入僵局。我希望执行能够等到释放该行上的所有其他锁为止。
服务器日志通常为此显示几个(> 1)冲突的事务。但是与用户一起进行的所有交易也应如上所述锁定行。
如何发生上述死锁?如何避免这些死锁?
编辑:令人惊讶的是,服务器日志显示给我的其他进程的锁也位于完全不同的表中,例如:
HINT: See server log for query details.
CONTEXT: while locking tuple (2892,8) in relation "account"
LOCATION: DeadLockReport, deadlock.c:1146
STATEMENT: SELECT * FROM account WHERE id = 197375 FOR UPDATE
LOG: 00000: process 17583 detected deadlock while waiting for ShareLock on transaction 1091990904 after 1000.057 ms
DETAIL: Process holding the lock: 17438. Wait queue: .
CONTEXT: while updating tuple (4588,22) in relation "subscription"
编辑2:我在日志中发现了第二个死锁,这很有趣:
冲突的过程A:
SQL statement "SELECT 1 FROM ONLY "public"."account" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"
SQL statement "WITH inserted_rows AS (
INSERT INTO payment_token (
account_id, ..., blocking_time
)
VALUES (
account_id, ..., the_blocking_time
)
RETURNING *
)
SELECT * FROM inserted_rows"
第一个语句不是直接来自我的代码,而第二个语句是存储函数的一部分。
冲突的流程B:
UPDATE account SET address_id = $2, update_time = CURRENT_TIMESTAMP WHERE id = $1