我有一个表foo_bar
和另一个表spam_eggs
,fb
外键指向foo_bar
. spam_eggs
当删除相关行时,行将被级联spam_eggs.fb
删除。
我正在使用 PostgreSQL。
在一个事务中,我曾经SELECT... FOR UPDATE
锁定spam_eggs
一行。在此事务期间,另一个事务已尝试DELETE FROM...
与foo_bar
我的锁定行相关。这会触发错误,还是我锁定的行会导致查询阻塞,直到我的原始更新事务结束?
我有一个表foo_bar
和另一个表spam_eggs
,fb
外键指向foo_bar
. spam_eggs
当删除相关行时,行将被级联spam_eggs.fb
删除。
我正在使用 PostgreSQL。
在一个事务中,我曾经SELECT... FOR UPDATE
锁定spam_eggs
一行。在此事务期间,另一个事务已尝试DELETE FROM...
与foo_bar
我的锁定行相关。这会触发错误,还是我锁定的行会导致查询阻塞,直到我的原始更新事务结束?
试试看。打开psql
并进行一些设置:
CREATE TABLE foo_bar(id integer primary key);
CREATE TABLE spam_eggs(
foo_bar_id integer not null references foo_bar(id) on delete cascade
);
INSERT INTO foo_bar (id) VALUES (1),(2),(3),(4);
INSERT INTO spam_eggs(foo_bar_id) VALUES (1),(2),(3),(4);
然后打开另一个 psql 连接。BEGIN
双方的交易。
SELECT 1 FROM spam_eggs WHERE foo_bar_id = 4 FOR UPDATE;
DELETE FROM foo_bar WHERE id = 4;
您将看到第二个语句阻塞在第一个语句上。那是因为DELETE
onfoo_bar
级联到spam_eggs
并尝试使用外键引用锁定行,以便它可以删除它。那把锁挡在SELECT ... FOR SHARE
.
一般来说,尝试在所有这些情况下进行测试:
BEGIN ISOLATION LEVEL READ COMMITTED
和第一个问题ROLLBACK
BEGIN ISOLATION LEVEL READ COMMITTED
和第一个问题COMMIT
BEGIN ISOLATION LEVEL SERIALIZABLE
和第一个问题ROLLBACK
BEGIN ISOLATION LEVEL SERIALIZABLE
和第一个问题COMMIT
以确保您知道会发生什么。如果您在测试之前对预期发生的事情进行推理,这对您的学习也有好处。
在这种情况下,隔离级别READ COMMITTED
和SERIALIZABLE
隔离级别将表现相同。但是,如果您实际上执行了操作UPDATE
,SELECT ... FOR UPDATE
那么COMMIT
它们的行为会有所不同;该READ COMMITTED
版本将DELETE
成功,而该SERIALIZABLE
版本将失败:
regress=# BEGIN ISOLATION LEVEL SERIALIZABLE;
regress=# DELETE FROM foo_bar WHERE id = 4;
ERROR: could not serialize access due to concurrent update
CONTEXT: SQL statement "DELETE FROM ONLY "public"."spam_eggs" WHERE $1 OPERATOR(pg_catalog.=) "foo_bar_id""