我希望更好地理解Postgres中的锁定机制。
假设一棵树可以有苹果(通过对苹果表的外键)。当选择更新一棵树时,似乎会获取对一个苹果的锁定。但是,即使其他人已经持有该苹果上的锁定,该操作也不会被阻塞。
为什么会这样呢?
附注:请不要建议删除“选择进行更新”。
场景
Transaction 1 Transaction 2
BEGIN .
update apple; .
. BEGIN
. select tree for update;
. update apple;
. --halts because of the other transaction locking an apple
update apple; .
-- deadlock .
COMMIT
--transaction succeeds
代码
如果你想在你的postgres中尝试它 - 这是一段你可以复制/粘贴的代码。
我有一个以下的数据库模式
CREATE TABLE trees (
id integer primary key
);
create table apples (
id integer primary key,
tree_id integer references trees(id)
);
而且非常简单的数据
insert into trees values(1);
insert into apples values(1,1);
有两个简单的事务。一个是更新苹果,第二个是锁定一棵树并更新一个苹果。
BEGIN;
UPDATE apples SET id = id WHERE id = 1;
-- run second transaction in paralell
UPDATE apples SET id = id WHERE id = 1;
COMMIT;
BEGIN;
SELECT id FROM trees WHERE id = 1 FOR UPDATE;
UPDATE apples SET id = id WHERE id = 1;
COMMIT;
当我运行它们时,在第一次事务的第二次更新时发生了死锁。
ERROR: deadlock detected
DETAIL: Process 81122 waits for ShareLock on transaction 227154; blocked by process 81100.
Process 81100 waits for ShareLock on transaction 227153; blocked by process 81122.
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."trees" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"
ShareLock
。第二个事务中的UPDATE
是否必要? - John Tseng