django select_for_update 获取关系锁
django select_for_update acquires relation lock
我有这个代码示例应该在 postgres 中使用行(元组)锁,但是它似乎需要 table(关系)锁:
with transaction.Atomic(savepoint=True, durable=False):
record = MyModel.objects.select_for_update().filter(pk='1234')
record.delete()
time.sleep(5)
raise Exception
通过查看交易期间的 pg_locks 我可以看到:
select locktype, database, relation::regclass, pid, mode, granted from pg_locks where pid <> pg_backend_pid();
据我所知,我应该在锁类型中看到“元组”,因为我只锁定特定的 row/s 而不是整个 table
要事第一
您实际上没有执行 SELECT FOR UPDATE
查询。
record = MyModel.objects.select_for_update().filter(pk='1234')
returns一个QuerySet
,没有执行任何查询。
record.delete()
只执行一个 DELETE
命令。
- 一个
SELECT FOR UPDATE
查询会获得一个 relation
RowShareLock
。
- 您可以通过使用
.first()
执行 QuerySet
来验证这一点,即 record = MyModel.objects.select_for_update().filter(pk='1234').first()
。
- 您可以使用 log all sql queries 来验证这一点。
行级(元组)锁
已获取行级 FOR UPDATE
锁,但未显示在您的 pg_locks
视图中(它也未显示在我的视图中)。相反,我们看到 transactionid
ExclusiveLock
(和 virtualxid
ExclusiveLock
)。
来自 https://www.postgresql.org/docs/9.3/view-pg-locks.html:
Although tuples are a lockable type of object, information about row-level locks is stored on disk, not in memory, and therefore row-level locks normally do not appear in this view. If a transaction is waiting for a row-level lock, it will usually appear in the view as waiting for the permanent transaction ID of the current holder of that row lock.
来自https://www.postgresql.org/docs/9.4/explicit-locking.html:
FOR UPDATE
...
The FOR UPDATE
lock mode is also acquired by any DELETE
on a row ...
您可以在您的 psql 终端中通过 运行 凭经验验证这一点:
- 之前
record.delete()
SELECT FROM mymodel WHERE id='1' FOR UPDATE;
有效。
SELECT FROM mymodel WHERE id='1234' FOR UPDATE;
有效。
- 在
record.delete()
之后
SELECT FROM mymodel WHERE id='1' FOR UPDATE;
有效。
SELECT FROM mymodel WHERE id='1234' FOR UPDATE;
无效。
Table 级(关系)锁
relation
AccessShareLock
似乎是为您未在代码示例中显示的 SELECT
查询获取的,例如MyModel.objects.filter(pk='1234').first()
.
relation
RowExclusiveLock
为 DELETE
命令获取。
虽然这些是table级别的锁,但它们只与EXCLUSIVE
and/or ACCESS EXCLUSIVE
锁冲突,大多数其他DQL(数据查询语言)不会获取这些锁) 和 DML(数据操作语言)命令。
来自https://www.postgresql.org/docs/9.4/explicit-locking.html:
ACCESS SHARE
Conflicts with the ACCESS EXCLUSIVE
lock mode only.
The SELECT
command acquires a lock of this mode on referenced tables. In general, any query that only reads a table and does not modify it will acquire this lock mode.
ROW EXCLUSIVE
Conflicts with the EXCLUSIVE
and ACCESS EXCLUSIVE
lock modes.
The commands UPDATE
, DELETE
, and INSERT
acquire this lock mode on the target table (in addition to ACCESS SHARE
locks on any other referenced tables). In general, this lock mode will be acquired by any command that modifies data in a table.
我有这个代码示例应该在 postgres 中使用行(元组)锁,但是它似乎需要 table(关系)锁:
with transaction.Atomic(savepoint=True, durable=False):
record = MyModel.objects.select_for_update().filter(pk='1234')
record.delete()
time.sleep(5)
raise Exception
通过查看交易期间的 pg_locks 我可以看到:
select locktype, database, relation::regclass, pid, mode, granted from pg_locks where pid <> pg_backend_pid();
据我所知,我应该在锁类型中看到“元组”,因为我只锁定特定的 row/s 而不是整个 table
要事第一
您实际上没有执行 SELECT FOR UPDATE
查询。
record = MyModel.objects.select_for_update().filter(pk='1234')
returns一个QuerySet
,没有执行任何查询。record.delete()
只执行一个DELETE
命令。
- 一个
SELECT FOR UPDATE
查询会获得一个relation
RowShareLock
。- 您可以通过使用
.first()
执行QuerySet
来验证这一点,即record = MyModel.objects.select_for_update().filter(pk='1234').first()
。
- 您可以通过使用
- 您可以使用 log all sql queries 来验证这一点。
行级(元组)锁
已获取行级 FOR UPDATE
锁,但未显示在您的 pg_locks
视图中(它也未显示在我的视图中)。相反,我们看到 transactionid
ExclusiveLock
(和 virtualxid
ExclusiveLock
)。
来自 https://www.postgresql.org/docs/9.3/view-pg-locks.html:
Although tuples are a lockable type of object, information about row-level locks is stored on disk, not in memory, and therefore row-level locks normally do not appear in this view. If a transaction is waiting for a row-level lock, it will usually appear in the view as waiting for the permanent transaction ID of the current holder of that row lock.
来自https://www.postgresql.org/docs/9.4/explicit-locking.html:
FOR UPDATE
...
The
FOR UPDATE
lock mode is also acquired by anyDELETE
on a row ...
您可以在您的 psql 终端中通过 运行 凭经验验证这一点:
- 之前
record.delete()
SELECT FROM mymodel WHERE id='1' FOR UPDATE;
有效。SELECT FROM mymodel WHERE id='1234' FOR UPDATE;
有效。
- 在
record.delete()
之后SELECT FROM mymodel WHERE id='1' FOR UPDATE;
有效。SELECT FROM mymodel WHERE id='1234' FOR UPDATE;
无效。
Table 级(关系)锁
relation
AccessShareLock
似乎是为您未在代码示例中显示的SELECT
查询获取的,例如MyModel.objects.filter(pk='1234').first()
.relation
RowExclusiveLock
为DELETE
命令获取。
虽然这些是table级别的锁,但它们只与EXCLUSIVE
and/or ACCESS EXCLUSIVE
锁冲突,大多数其他DQL(数据查询语言)不会获取这些锁) 和 DML(数据操作语言)命令。
来自https://www.postgresql.org/docs/9.4/explicit-locking.html:
ACCESS SHARE
Conflicts with the
ACCESS EXCLUSIVE
lock mode only.The
SELECT
command acquires a lock of this mode on referenced tables. In general, any query that only reads a table and does not modify it will acquire this lock mode.
ROW EXCLUSIVE
Conflicts with the
EXCLUSIVE
andACCESS EXCLUSIVE
lock modes.The commands
UPDATE
,DELETE
, andINSERT
acquire this lock mode on the target table (in addition toACCESS SHARE
locks on any other referenced tables). In general, this lock mode will be acquired by any command that modifies data in a table.