@den94ka

Как избежать одновременного UPDATE таблицы базы данных MySQL?

Разрабатываю браузерную игру, в которой есть рынок. На рынке продаются семена и каждый пользователь может выставить свои семена на продажу. Возник вопрос одновременного использования.

Таблица выглядит так:
id | user_id | amount
1 | 4 | 0
2 | 1 | 30
3 | 5 | 10


В php алгоритм действий такой:
1 - Выбираю первую запись в таблице, у которой amount > 0 (то есть еще есть семена на продаже)
2 - Обновляю запись в таблице, уменьшая ей amount

В этом случае, может быть такое, что одновременно несколько пользователей обратятся к рынку и получат одну и ту же запись. (А такое может быть, так как кнопка одна и действие простое).

То есть, алгоритм такой:
1 пользователь - SELECT * FROM market WHERE amount > 0 LIMIT 1
2 пользователь - SELECT * FROM market WHERE amount > 0 LIMIT 1
1 пользователь - UPDATE market SET amount = amount - 10 WHERE id LIKE id

И в этот момент второй пользователь тоже обновляет запись, но он не знает, что там количество семян уже уменьшилось. Как быть в этом случае?

Я копал в сторону следующего алгоритма:
1. Получаем amount последней записи и обнуляем ее
2. Затем обновляем amount (вычитаем купленные семена) и обновляем запись в таблице (возвращаем некупленные семена)

Но в таком случае (насколько я нагуглил) невозможно сделать SELECT перед UPDATE в одном запросе.

Как правильно это реализовать в MySQL? Может поменять алгоритм?
  • Вопрос задан
  • 686 просмотров
Решения вопроса 1
LaRN
@LaRN
Senior Developer
Транзакции всем хороши, но под нагрузкой приводят к замедлению работы приложения и иногда, если не правильно работать с запросами к deadlock-м.

Можно создать отдельную таблицу в которую записывать запросы пользователей на получение ресурса, например так:
идентификатор пользователя, идентификатор ресурса, статус заявки (в очереди, обработана, отклонена), дата и время заявки с точностью до миллисекунд (ну или числовое поле с автонумерацией).

При нажатии на "купить товар" операция выполняется в два шага, первый шаг - помещаем заявку пользователя в эту таблицу. (несколько пользователей могут придти за одним ресурсом и приоритет будет у того кто пришел первым)
Таблица нужна, чтобы не накладывать блокировок на таблицы БД (блокировки могут быть из-за открытой транзакции)

Далее второй шаг - запускаем процедуру получения статуса заявки (она должна вернуть ответ получил пользователь свой ресурс или нет, т.е. обработана его заявка успешно или отклонена).

Обработка заявок - это отдельный серверный процесс, он берет заявки по очереди поступления и обрабатывает (изменяет состояние ресурса в БД и состояние заявки) до тех пор пока у выбранного ресурса хватает количества, все пользователи которым не хватило ресурса получают сообщение о невозможности получить ресурс.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Почитайте о транзакциях, они блокируют поля, пока выполняется UPDATE.
Ответ написан
@ynblpb_spb
дятел php
Пользователь для покупки наверняка жмет на кнопку с указанием ID из таблицы market
Соот-но в момент покупки (перед update) делать еще раз select amount from market where id = 1)
и если amount > 0 то делать апдейт, в противном случае выводить пользователю "извините, уже кто-то купил"
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы