我在PostgreSQL 10.5数据库中有以下语句,该语句在repeatable read
事务中执行:
delete from task
where task.task_id = (
select task.task_id
from task
order by task.created_at asc
limit 1
for update skip locked
)
returning
task.task_id,
task.created_at
不幸的是,当我运行它时,有时会得到:
[67] ERROR: could not serialize access due to concurrent update
[67] STATEMENT: delete from task
where task.task_id = (
select task.task_id
from task
order by task.created_at asc
limit $1
for update skip locked
)
returning
task.task_id,
task.created_at
,这意味着该事务回滚,因为与此同时其他某个事务修改了该记录。 (我认为吗?)
我不太明白这一点。另一个事务如何修改用for update skip locked
选择并删除的记录?
答案 0 :(得分:2)
This quote from the manual 精确地讨论了您的情况:
UPDATE
,DELETE
,SELECT FOR UPDATE
和SELECT FOR SHARE
命令 在搜索目标行方面,其行为与SELECT
相同: 将仅查找在事务处理中已提交的目标行 开始时间。但是,这样的目标行可能已经被更新 到那时被另一个并发事务(或删除或锁定) 找到了。在这种情况下,可重复读事务将等待 要提交或回滚的第一个更新事务(如果是) 仍在进行中)。如果第一个更新程序回滚,则其效果 被否定,可重复读事务可以继续进行 更新最初找到的行。但是如果第一个更新程序提交 (并实际上更新或删除了该行,而不仅仅是锁定了该行),然后 可重复的读取事务将与消息一起回滚ERROR: could not serialize access due to concurrent update
意味着,由于并发写访问首先到达那里,因此您的事务无法锁定开头的行。 SKIP LOCKED
不能完全避免您这样做,因为自交易以来该行已被更改(并且更改已提交,因此释放了锁),因此可能没有锁可以跳过,并且仍然遇到序列化失败。开始。
同一语句在默认的READ COMMITTED
事务隔离下应该可以正常工作。相关: