#sql #postgresql #concurrency #locking
Вопрос:
У меня есть унаследованный код со следующим:
const sql = `UPDATE fqdn SET lock = $1
FROM (SELECT id FROM fqdn WHERE region = $2 AND lock IS NULL AND expires < $3 OR lock = $1 LIMIT $4) AS expired
WHERE fqdn.id = expired.id
RETURNING fqdn.id, fqdn.config, fqdn.data`;
Существует несколько микросервисов, выполняющих этот запрос в одной и той же базе данных.
Идея создателя состоит в том, чтобы заблокировать пакет строк, с которыми будет работать каждая микросервисная служба, полем блокировки, которое является полным доменным именем ($1 => полное доменное имя) машины, на которой запущена микросервисная служба.
Похоже, однако, что иногда два микросервиса могут работать над одним и тем же пакетом. Есть ли способ сериализовать его так, чтобы параллельный второй поток выполнял выбор только после того, как первый завершил обновление блокировки?
Спасибо
Ответ №1:
В запросе действительно есть условие гонки. Два одновременных выполнения могут найти одну и ту же строку в подзапросе, и, хотя одно из обновлений будет заблокировано, в конечном итоге оно продолжит обработку, когда завершится другая транзакция.
Вы должны добавить следующее в подзапрос:
FOR NO KEY UPDATE SKIP LOCKED
Это гарантировало бы, что никакие два запроса не смогут возвращать одни и те же строки.
Комментарии:
1. Спасибо, Лоренц, похоже, это хорошо работает