Я чув про проблеми з одночасністю, як у 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
таблицю, це ніколи не повинно виникати.