oro*_*aki 5 sql postgresql select transaction-isolation
我有一个表foo_bar,另一个表spam_eggs有fb外键指向foo_bar.spam_eggs删除相关的行时会级联spam_eggs.fb删除.
我正在使用PostgreSQL.
在我曾经用于SELECT... FOR UPDATE锁定spam_eggs行的事务中.在此事务的持续时间内,另一个事务已尝试DELETE FROM...与foo_bar我的锁定行相关联.这会触发错误,还是我的锁定行会导致查询阻塞直到我的原始更新事务结束?
Cra*_*ger 13
试试看吧.打开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);
Run Code Online (Sandbox Code Playgroud)
然后打开另一个psql连接.BEGIN两者中的交易.
SELECT 1 FROM spam_eggs WHERE foo_bar_id = 4 FOR UPDATE;DELETE FROM foo_bar WHERE id = 4;您将看到第二个语句在第一个语句上阻塞.这是因为它DELETE与foo_bar级别spam_eggs引用一起并尝试使用外键引用来锁定行,因此它可以删除它.那把锁挡在了锁上SELECT ... FOR SHARE.
一般来说,尝试在所有这些情况下进行测试:
BEGIN ISOLATION LEVEL READ COMMITTED首先发布的ROLLBACKBEGIN ISOLATION LEVEL READ COMMITTED首先发布的COMMITBEGIN ISOLATION LEVEL SERIALIZABLE首先发布的ROLLBACKBEGIN 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""
Run Code Online (Sandbox Code Playgroud)