我有一个通过以下命令在PostgreSQL中创建和填充的表:
CREATE TABLE my_lock (
id integer,
CONSTRAINT id_pkey PRIMARY KEY (id)
) ;
INSERT INTO my_lock VALUES (1) ;
INSERT INTO my_lock VALUES (2) ;
此表由以下Django模型
表示from django.db import models
from django.db import transaction
class MyLock(models.Model):
class Meta(object):
db_table = 'my_lock'
接下来,我有以下方法:
from contextlib import contextmanager
@contextmanager
def acquire_lock():
with transaction.atomic():
lock = MyLock.objects.select_for_update().filter(id=1).first()
yield lock
def first_method():
print "In first method"
with acquire_lock():
print "Lock acquired in first_method()"
second_method()
def second_method():
print "In second method"
first_method()
acquire_lock()
方法是一个Python生成器,它在事务中运行SELECT FOR UPDATE
查询。这应该锁定id = 1的行,并且因为在调用yield lock
时,事务没有完成,继续保持锁定。
因此,如果我们致电first_method()
,则应打印以下输出 :
In first method
Lock acquired in first_method()
In second method
In first method
然而,在调用first_method()
时在现实中,会打印以下内容:
In first method
Lock acquired in first_method()
In second method
In first method
Lock acquired in first_method()
In second method
In first method
Lock acquired in first_method()
In second method
In first method
Lock acquired in first_method()
In second method
(这一直持续到RuntimeError: maximum recursion depth exceeded
)
我在这里遗漏了一些东西。怎么会发生这种情况?如何多次获取PostgreSQL中的行锁?
编辑:
如果我将first_method()
更改为:
def first_method():
print "In first method"
with acquire_lock():
print "Lock acquired in first_method()"
i = 1
while True:
i = i + 1
i = i - 1
,现在从两个不同的终端(或shell)调用first_method()
,
其中一个打印出以下内容:
In first method
Lock acquired in first_method()
第二个打印出以下内容:
In first method
因此,锁在这种情况下有效,但不能递归工作。
答案 0 :(得分:3)
这就是锁的工作方式。在Row level locks:
请注意,事务可以在同一行上保存冲突的锁,即使在不同的子事务中也是如此;
您的代码在单个事务中运行。 Postgres中的锁旨在防止与其他事务冲突。因此,单个事务可以多次获取相同的锁,但只要当前事务持有,其他事务就无法获取该锁。