我想更好地理解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"
解决方法
只是一个疯狂的猜测:你遇到了与实现细节相关的问题……
具体来说,update语句的select树获取树上的独占锁. update apples语句获得对相关苹果的独占锁定.
当您在Apple上运行更新时,Postgres的每行相关的外键触发器会触发,以确保tree_id存在.我不记得他们的精确名字在我的头顶,但它们在目录中,文档中有一些零碎的部分明确地或隐含地引用它们,例如:
create constraint trigger ... on ... from ...
http://www.postgresql.org/docs/current/static/sql-createtrigger.html
无论如何,这些触发器将运行相当于以下内容:
select exists (select 1 from trees where id = 1);
这就解决了你的问题:由于select for update的独占访问使得它等待事务2释放树上的锁以便最终确定其对apple的更新语句,但事务2正在等待事务1完成以便获取对苹果的锁定,以便开始对苹果进行更新.
结果,Postgres陷入僵局.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。