Здесь есть оговорка, которая была упомянута в комментариях.Вы должны использовать изолированную транзакцию 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, чтобы упростить ситуацию, и тогда любая фактическая ошибка будет действительно неожиданной.