选择...以便在可重复读取事务中锁定更新跳过

时间:2018-11-13 19:58:09

标签: sql postgresql transactions isolation-level locks

我在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选择并删除的记录?

1 个答案:

答案 0 :(得分:2)

This quote from the manual 精确地讨论了您的情况

  

UPDATEDELETESELECT FOR UPDATESELECT FOR SHARE命令   在搜索目标行方面,其行为与SELECT相同:   将仅查找在事务处理中已提交的目标行   开始时间。但是,这样的目标行可能已经被更新   到那时被另一个并发事务(或删除或锁定)   找到了。在这种情况下,可重复读事务将等待   要提交或回滚的第一个更新事务(如果是)   仍在进行中)。如果第一个更新程序回滚,则其效果   被否定,可重复读事务可以继续进行   更新最初找到的行。但是如果第一个更新程序提交   (并实际上更新或删除了该行,而不仅仅是锁定了该行),然后   可重复的读取事务将与消息一起回滚

ERROR:  could not serialize access due to concurrent update

意味着,由于并发写访问首先到达那里,因此您的事务无法锁定开头的行。 SKIP LOCKED不能完全避免您这样做,因为自交易以来该行已被更改(并且更改已提交,因此释放了锁),因此可能没有锁可以跳过,并且仍然遇到序列化失败。开始。

同一语句在默认的READ COMMITTED事务隔离下应该可以正常工作。相关: