ВЫБРАТЬ ... ДЛЯ ПЕРЕХОДА ОБНОВЛЕНИЯ, ЗАБЛОКИРОВАННОГО в транзакциях REETABLE READ - PullRequest
0 голосов
/ 13 ноября 2018

У меня есть следующий оператор в моей базе данных 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 голосов
/ 13 ноября 2018

Эта цитата из руководства обсуждает ваш случай точно :

Команды

UPDATE, DELETE, SELECT FOR UPDATE и SELECT FOR SHARE ведут себя так же, как SELECT в плане поиска целевых строк: они найдет только целевые строки, которые были зафиксированы на момент транзакции начальное время. Однако такая целевая строка, возможно, уже была обновлена (или удален или заблокирован) другой параллельной транзакцией к тому времени нашлось. В этом случае повторяемая транзакция чтения будет ждать для первой транзакции обновления для фиксации или отката (если это все еще в процессе). Если первый апдейтер откатывается, то его эффекты отменяются, и повторяемая операция чтения может продолжаться с обновление первоначально найденной строки. Но если первый обновитель фиксирует (и фактически обновил или удалил строку, а не просто заблокировал ее), затем Повторяемая транзакция чтения будет откатана с сообщением

ERROR:  could not serialize access due to concurrent update

Это означает, что вашей транзакции не удалось заблокировать строку для начала - из-за одновременного доступа к записи, который был получен первым. SKIP LOCKED не может спасти вас от этого полностью, так как может не быть блокировки, чтобы пропустить больше, и мы все еще сталкиваемся с ошибкой сериализации, если строка уже была изменена (и изменение зафиксировано - следовательно, блокировка снята) с момента запуска транзакции.

Тот же оператор должен прекрасно работать со стандартной READ COMMITTED изоляцией транзакции. Связанный:

...