PostgreSQL已读取已提交的隔离级别。现在我有一个由单个DELETE语句组成的事务,这个delete语句有一个子查询,该子查询由SELECT语句组成,用于选择要删除的行。
我是否必须在select语句中使用FOR UPDATE才能与其他事务冲突?
我的想法如下:首先从表中读出相应的行,然后在第二步中删除这些行,这样另一个事务就可能会干扰。
那么简单的DELETE FROM myTable WHERE id = 4语句怎么样?我是否还必须使用FOR UPDATE?
答案 0 :(得分:3)
我是否必须在select语句中使用FOR UPDATE 与其他交易没有冲突?
“与其他交易没有冲突”对您意味着什么?您可以通过打开两个终端并在每个终端中执行语句来测试它。正确交错,DELETE语句将使“其他事务”(隔离级别设置为READ COMMITTED
的那个)等到提交或回滚。
sandbox=# set transaction isolation level read committed;
SET
sandbox=# select * from customer;
date_of_birth
---------------
1996-09-29
1996-09-28
(2 rows)
sandbox=# begin transaction;
BEGIN
sandbox=# delete from customer
sandbox-# where date_of_birth = '1996-09-28';
DELETE 1
sandbox=# update customer
sandbox-# set date_of_birth = '1900-01-01'
sandbox-# where date_of_birth = '1996-09-28';
(Execution pauses here, waiting for transaction in other terminal.)
sandbox=# commit;
COMMIT
sandbox=#
UPDATE 0
sandbox=#
请参阅下面的文档。
那么简单的DELETE FROM myTable WHERE id = 4语句怎么样?做 我还必须使用FOR UPDATE?
没有DELETE . . . FOR UPDATE
这样的陈述。
当您阅读有关数据库更新时,您需要对上下文敏感。 更新可能意味着对数据库的任何更改;它可以包括插入,删除和更新行。在下面引用的文档中,“就像更新一样锁定”明确地讨论了UPDATE和DELETE语句等等。
FOR UPDATE会导致SELECT语句检索到的行 锁定好像是为了更新。这可以防止它们被修改或 在当前交易结束之前被其他交易删除。那 是,尝试UPDATE,DELETE,SELECT FOR UPDATE的其他事务, SELECT FOR NO KEY UPDATE,SELECT for SHARE或SELECT FOR KEY for KEY SHARE 这些行将被阻止,直到当前事务结束。 FOR UPDATE锁定模式也可以通过行上的任何DELETE获取,也可以通过 修改某些列上的值的UPDATE。目前, 考虑用于UPDATE案例的列集是具有的列 可以在外键中使用的唯一索引(所以部分 不考虑索引和表达指数),但这可能 改变未来。此外,如果UPDATE,DELETE或SELECT FOR UPDATE 来自另一个事务已经锁定了一个或多个选定的行, SELECT FOR UPDATE将等待另一个事务完成,并且 然后将锁定并返回更新的行(如果行是,则不返回行 删除)。
答案 1 :(得分:2)
简短版本:子选择中的FOR UPDATE
不是必需的,因为DELETE
实现已经进行了必要的锁定。这将是多余的。
理想情况下,您应该阅读并消化Concurrency Control以了解SQL引擎如何处理并发问题。
特别是对于你提到的情况,我认为这些摘录是最相关的,Read Committed Isolation Level:
UPDATE,DELETE,SELECT FOR UPDATE和SELECT FOR SHARE命令 在搜索目标行方面表现与SELECT相同:它们 将只查找从命令start开始提交的目标行 时间。
但是,这样的目标行可能已经更新(或者 当它被另一个并发事务删除或锁定时 找到。在这种情况下,可能的更新程序将等待第一个 更新事务以提交或回滚(如果它仍在 进度)。
因此,只要它尝试删除另一个之前已处理过的行,就会等待其中一个并发DELETE等待。只有当另一个提交或回滚时,此等待才会结束。在某种程度上,这意味着引擎“检测到冲突”并序列化了两个DELETE以处理该冲突。
如果第一个更新程序回滚,那么它的效果是 否定,第二个更新程序可以继续更新 最初找到了一排。 如果第一个更新程序提交,则第二个更新程序 如果第一个更新程序删除了,将忽略该行,否则它将 尝试将其操作应用于行的更新版本。
在你的场景中,在第一个DELETE提交并且第二个被唤醒之后,第二个将无法删除它等待的行,因为它不再是最新的,它已经消失了。此隔离级别中的这不是错误。执行将继续执行其他行,其中一些也可能已消失。最终,它将报告此语句删除的实际行数,这可能与语句等待之前的子选择最初找到的数量不同。