Postgres не может сериализовать доступ из-за одновременного обновления - PullRequest
0 голосов
/ 11 июня 2018

У меня проблема с " Не удалось сериализовать доступ из-за одновременного обновления ".Я проверил журналы и ясно вижу, что две транзакции пытались обновить строку одновременно.

мой sql запрос

UPDATE sessionstore SET valid_until = %s WHERE sid = %s;

Как я могу сказать postgres "попробовать" обновить строку без каких-либо исключений?

Ответы [ 2 ]

0 голосов
/ 20 августа 2018

Здесь есть оговорка, которая была упомянута в комментариях.Вы должны использовать изолированную транзакцию REPEATABLE READ или выше.Зачем?Обычно это не требуется, если только у вас нет конкретной причины.

Ваша проблема исчезнет, ​​если вы будете использовать стандарт READ COMMITTED.Но все же лучше использовать SKIP LOCKED, чтобы избежать ожидания блокировки, избыточных обновлений и потери трафика WAL.

Начиная с Postgres 9.5+, есть гораздо лучший способ справиться с этим, который будет выглядеть следующим образом:

UPDATE sessionstore
SET valid_until = %s
WHERE sid = (
    SELECT sid FROM sessionstore
    WHERE sid = %s
    FOR UPDATE SKIP LOCKED
);

Первая транзакция, получившая блокировку в SELECT FOR UPDATE SKIP LOCKED, приведет к тому, что любая конфликтующая транзакция ничего не выберет, что приведет к неработоспособности.В соответствии с запросом, оно не будет выдавать исключение.

См. Примечания SKIP LOCKED здесь: https://www.postgresql.org/docs/current/static/sql-select.html

Кроме того, рекомендации по поводу точки сохранения недостаточно конкретны.Что если обновление завершится неудачей по какой-либо причине, кроме ошибки сериализации?Как настоящий тупик?Вы не хотите просто молча игнорировать все ошибки.Но в целом это тоже плохая идея - обработчик исключений или точка сохранения для каждого обновления строки - это много лишних затрат, особенно если у вас большой трафик.Вот почему вы должны использовать READ COMMITTED и SKIP LOCKED, чтобы упростить ситуацию, и тогда любая фактическая ошибка будет действительно неожиданной.

0 голосов
/ 11 июня 2018

Канонический способ сделать это - установить контрольную точку перед UPDATE:

SAVEPOINT x;

Если обновление завершится неудачно,

ROLLBACK TO SAVEPOINT x;

и транзакция может продолжиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...