2013-11-24 2 views
0

Итак, моя команда разрабатывает API на PHP. Моя основная забота - это то, что случается, когда 2 человека требуют обновить ту же строку.Несколько приложений, получающих одни и те же данные

Таким образом, если один вызов API выполнит чтение, а затем информацию о процессе, то напишите, что произойдет, если другой вызов API сделает то же самое для одной и той же строки данных. Мы используем Postgres OR Mysql.

User has 100 dollars. 
API Call 1 to ADD 20 1 reads 100. 
API Call 2 to Subtract 20 reads 100. 
API Call 1 writes 120; 
API Call 2 write 80;(instead of 100); 

Я знаю, что есть решение, связанное с блокировкой столов или строк, будет ли это решить мою проблему?

Мне нужно решение, в котором API-вызов 2 не прерывается, а скорее ждет или повторяет попытку.

[EDIT]

я должен идти более подробно о том, что мы делаем. Это браузерная игра MMO, в которой есть 2 части. PHP REST API и Java-сервер.

Браузер делает API AJAX GET API ex. : Build Factory за $ 40k PHP API Проверьте, достаточно ли средств и возвращаете JSON. SO - 40 тысяч долларов от игрока.

Наши тики сервера имеют одновременные вызовы базы данных с использованием функции boneCP для обновления значений, таких как средства.

Итак, из моего предыдущего примера CALL 1 будет нашим API-интерфейсом PHP, а CALL 2 будет тиком сервера.

+0

Пересмотреть свойства ACID и убедиться, что они сохранены. После этого проверка SS2PL –

+0

С помощью Postgres, использующего сериализуемый уровень изоляции, вы не сможете записать неправильное значение (вам придется иметь дело с ошибками) –

ответ

3

Вы должны узнать о transactions, transaction isolation и explicit row-level locking:

select ... for update 

В вашем случае, а также посмотреть в использовании выражений. Ваша жизнь была бы намного проще, если вы выпущены как коснуться:

update account set amount = amount - 20 where id = ? 
+0

Я использовал транзакции в MySQL InnoDB, но как транзакция прекращает это. Вызов API раздельный, они не выполняются с тем же вызовом. (Также ваша сумма = сумма - ввод - это что-то простое и легкое, и я не могу поверить, что я этого не заметил. (Также я видел, что вы обновили) – c3cris

+1

Если у вас есть транзакция и выбор для обновления, вызов 2 не может читать строка до завершения вызова 1. Аналогично, если две параллельные транзакции являются сериализуемыми (вы много читаете, чтобы сделать. Не пропустите этот шаг.) –

+0

Я понял, что 2-й вызов не может быть прочитан из-за блокировка строк, но означает ли это, что он не работает или ждет разблокировки? – c3cris

2

Ваш API плохо разработаны и должна быть исправлена. Вместо:

  1. У пользователя есть 100 долларов.
  2. API вызовов 1 к ADD 20 1 считывает 100.
  3. API вызова 2 вычитать 20 считывает 100.
  4. API вызовов 1 пишет 120;
  5. API Call 2 написать 80; (вместо 100);

Вместо этого вы должны иметь поток, как:

  1. Пользователь имеет 100 долларов
  2. API вызова 1 к "Добавить 20 на счет 1", так что приходится 1 изменения от 100 до 120 и возвращает новое значение 120
  3. API вызова 2 на «Вычитание 20 со счета 1», так что счета 1 изменения от 120 до 100, и возвращает новое значение 100

Точно так же, если вы тра nsferring между двумя учетными записями вы бы всегда использовали вызов API, который делает перевод вместо того, чтобы делать добавление, затем отдельный вычитание или наоборот.

Другими словами, вам необходимо переконфигурировать ваш API так, чтобы ваше состояние базы данных было согласовано в начале и конце каждого вызова API. Чтобы гарантировать, что вызов API, который использует несколько операторов SQL, будет согласован, даже если вы прервали половину пути, вы должны wrap the API call's work up in a transaction, и если вы не собираетесь использовать изоляцию SERIALIZABLE, выполните соответствующие команды SELECT ... FOR UPDATE, если вы будете делать чтение-изменение-запись в рамках транзакции.

Клиентские приложения должны избегать read-modify-write cycles.

В ситуациях, когда чтение-изменение-запись неизбежно, поэтому два или более вызова API должны быть согласованными, вы должны использовать optimistic concurrency control для защиты от сбоев обновления. В этом случае ваш сценарий будет выглядеть следующим образом:

  1. Пользователь имеет 100 долларов.
  2. API вызовы 1 считывают счета 1, получает значение 100 и rowversion 1
  3. API вызовы 2 считывают счета 1, получают значение 100 и rowversion 1
  4. API вызовов 1 добавляет 20 к извлеченного значения 100, посылает новое значение 120 и rowversion 1. Преуспевает, потому что отправленная rowversion равна in-database rowversion.
  5. API Call 2 вычитает 20 из извлеченного значения 100, отправляет новое значение 80 и новую строку преобразования 1. сбой с возвратом ошибки, потому что преобразование базы данных более новое, чем отправленное rowversion, поэтому кто-то еще изменил строку, так как мы ее извлекли. Второй вызывающий API должен снова получить строку и повторить попытку.
+0

Хорошо, что у нас есть скрипт PHP API, который прослушивает AJAX, вызывает и читает и записывает в базу данных. И у нас также есть Java-сервер, который постоянно читает и обновляет базу данных на основе нашего алгоритма. Это, по сути, браузерная игра mmo, где для вызова AJAX GET API можно «построить здание за 40 тыс. Долларов», а затем обновить базу данных для игрока. Но пока все это происходит, сервер Java обрабатывает тики сервера для постоянного дохода игрока для игрока X каждые 5 секунд. Доход - всего лишь 1 пример. (Я хотел дать вам идею, что происходит, если есть лучший способ) – c3cris

+0

@CrisG Ну, с одной стороны, если доход постоянный, вы можете хранить время с последней транзакции + уровень дохода, таким образом, вы не обновляете DB каждые 5 секунд для каждого игрока, чтобы просто обновить что-то, что вы можете рассчитать тривиально «на лету». –

+0

Да, мы это выяснили с использованием штампов времени. – c3cris

Смежные вопросы