На сайте авиакомпании произошел сбой. Два человека одновременно забронировали последнее оставшееся место в самолете — и оба оплатили билет. Но затем один из пассажиров получил ошибку о том, что его место уже занято. В итоге авиакомпания понесла репутационные и финансовые потери.
Интересно, а в реальных компаниях такой же код? Или это просто для этой конкретной задачи?
А вот этого мы никогда не узнаем)
Нужно использовать транзакции в PostgreSQL с уровнем изоляции SERIALIZABLE или REPEATABLE READ
В данном случае рекомендуется использовать FOR UPDATE для блокировки записей при выполнении SELECT
`SELECT * FROM tickets WHERE place=%place AND flight_id=%flight_id FOR UPDATE`
`UPDATE tickets SET reserved_by=%user_id WHERE id=%ticket_id`
.
Такие штуки надо осуществлять транзакциями — операциями, которые могут выполниться успешно целиком или не выполниться вовсе. Должно быть что‑то вроде:
try:
# Начинаем транзакцию. Важно, чтобы база данных поддерживала транзакции.
db.begin_transaction()
# Запрашиваем базу данных. Что‑то вроде…
ticket = db.execute(SQL-запрос здесь).fetchone()
if ticket:
db.rollback_transaction()
return "Билет не найден"
Всё нормально, осуществляем запись…
except Exception as e:
db.rollback_transaction()
finally
db.end_transaction()
транзакция без изоляции не поможет. Здесь важна блокировка таблицы во время чтения.
Транзакция просто отменить обновление если будет ошибка во время запроса
недавно узнала, что абсолютно все авиакомпании продают намного больше билетов, чем есть на самом деле. непонятно только зачем??