Я чув про проблеми з одночасністю, як у MySQL, раніше. У Postgres не так.
Досить вбудованих блоків на рівні рядків на рівні READ COMMITTEDізоляції транзакцій за замовчуванням .
Я пропоную одне твердження з CTE, що модифікує дані (те, чого у MySQL також немає), оскільки зручно передавати значення з однієї таблиці в іншу безпосередньо (якщо вам це потрібно). Якщо вам нічого не потрібно з couponтаблиці, ви можете також використовувати транзакцію з окремими UPDATEі INSERTвиписками.
WITH upd AS (
UPDATE coupon
SET used = true
WHERE coupon_id = 123
AND NOT used
RETURNING coupon_id, other_column
)
INSERT INTO log (coupon_id, other_column)
SELECT coupon_id, other_column FROM upd;
Має бути рідкісною річ, що більше однієї транзакції намагаються викупити той самий купон. У них є унікальний номер, чи не так? Більше однієї транзакції, яка намагається здійснити в той самий момент часу, має бути набагато рідше. (Можливо, помилка програми чи хтось намагається грати в систему?)
Як би там не було, UPDATEєдиний успіх здійснює саме одна транзакція, незважаючи ні на що. UPDATEНабуває блокування на рівні рядків на кожній цільовій рядку перед оновленням. Якщо паралельна транзакція намагається виконати UPDATEтой самий рядок, вона побачить блокування в рядку і чекатиме завершення ( ROLLBACKабо COMMIT) блокування транзакції , а потім буде першою у черзі блокування:
Якщо це здійснено, перевірте умову. Якщо це все-таки NOT usedзамкніть рядок і продовжуйте. В іншому випадку UPDATEтепер не знайдеться відповідного рядка і нічого не робить, не повертаючи жодного рядка, тому INSERTтакож нічого не робить.
Якщо відкотився, заблокуйте рядок і продовжуйте.
Немає потенціалу для перегонів .
Не існує потенціалу для глухого кута, якщо ви не введете більше записів в одну транзакцію або іншим чином заблокуєте більше рядків, ніж лише одну.
INSERTЄ безтурботним. Якщо з якихось помилок coupon_idвже є в logтаблиці (і у вас є UNIQUE або PK обмеження log.coupon_id), вся транзакція буде скасована назад після унікального порушення. Вказує на незаконне стан у вашій БД. Якщо вищезазначене твердження є єдиним способом запису в logтаблицю, це ніколи не повинно виникати.