В общем, вы должны сделать это с одним оператором UPDATE. На UPDATE обычно не влияют строки, которые могли измениться во время выполнения оператора UPDATE, однако, полезно прочитать об уровнях изоляции транзакций здесь .
Предполагается, что вы используете настройку Read Committed по умолчанию, вот что она говорит:
Read Committed - уровень изоляции по умолчанию в PostgreSQL. Когда
транзакция выполняется на этом уровне изоляции, запрос SELECT видит только
данные зафиксированы до начала запроса;
А что касается ОБНОВЛЕНИЯ:
Команды UPDATE, DELETE, SELECT FOR UPDATE и SELECT FOR SHARE
ведут себя так же, как SELECT с точки зрения поиска целевых строк: они
найдет только те строки назначения, которые были зафиксированы на момент запуска команды
время. Однако такая целевая строка, возможно, уже была обновлена (или
удален или заблокирован) другой параллельной транзакцией к тому времени, когда она
найденный. В этом случае потенциальный обновитель будет ждать первого
обновление транзакции для фиксации или отката (если она все еще находится в
прогресс). Если первый апдейтер откатывается, то его эффекты
отрицается, и второй обновитель может продолжить обновление
изначально найденный ряд. Если первый обновитель фиксирует, второй обновитель фиксирует
проигнорирует строку, если первый обновитель удалил ее, в противном случае она будет
попытаться применить свою операцию к обновленной версии строки.
условие поиска команды (предложение WHERE) переоценивается в
посмотреть, соответствует ли обновленная версия строки поиску
состояние. Если это так, второй модуль обновления продолжает свою работу,
начиная с обновленной версии строки. (В случае выбора
Для обновления и выбора для обмена, это означает, что это обновленная версия
строки, которая заблокирована и возвращена клиенту.)
Так что в вашем сценарии, одно ОБНОВЛЕНИЕ должно быть хорошо.
Имейте также в виду, что существует так называемый оператор SELECT FOR UPDATE
, который блокирует выбранные вами строки. Вы можете прочитать об этом здесь .
Сценарий, в котором вам нужно будет использовать эту функцию, будет в системе бронирования. Рассмотрим этот пример:
- Выполните
SELECT
, чтобы узнать, доступен ли номер XYZ для бронирования на дату X.
- Помещение доступно. Выполните
UPDATE
запрос, чтобы забронировать комнату.
Видите ли вы здесь потенциальную проблему? Если между шагами 1 и 2 комната забронирована другой транзакцией, то когда мы достигаем шага 2, мы действуем в предположении, которое больше не действует, а именно, что комната доступна.
Однако, если на шаге 1 вместо этого мы используем оператор SELECT FOR UPDATE, мы гарантируем, что никакая другая транзакция не сможет заблокировать эту строку, поэтому, когда мы перейдем к UPDATE строки, мы знаем, что это безопасно.
Но, опять же, в вашем сценарии этот SELECT FOR UPDATE не нужен, потому что вы делаете все в одном выражении и ничего не проверяете заранее.