Как избежать конфликта данных MySQL при запросах от нескольких клиентов одновременно

Допустим у нас есть SQL таблица users, которая содержит строки id и respect. Есть скрипт обработчик на php который по запросу от клиента добавляет или понижает значение respect, причем если значение respect больше 100, то повышает или понижает на 10, а если меньше, то на 5. Пример на php будет выглядеть так

/*1*/$id = $_POST['id'];
/*2*/$type = $_POST['type'];
/*3*/$user = R::findOne('users', 'id = ?', array($id));//Запрос к БД за данных о /*1*/пользователе
/*4*/$current_respect = $user->respect;
/*5*/$rate = 5;
/*6*/if($current_respect > 100){
/*7*/    $rate = 10;
/*8*/}
/*9*/if($_POST['type'] == 'increase'){
/*10*/    $user->respect += rate;
/*11*/}elseif($_POST['type'] == 'decrease'){
/*12*/    $user->respect -= rate;
/*13*/}
/*14*/R::store($user);

При достаточно большом количестве запросов от разных пользователей может случиться так, что после проверки величины respect, но до сохранения его нового значения, другая копия скрипта при обработке другого запроса также проверит старое значение и изменять будет его, в результате чего на выходе мы получим два разных значения, которые не учитывали изменения друг друга?

Например:

  1. В данный момент времени у user с id = 1 значение respect равно 101
  2. Почти одновременно делается два запроса разными клиентами. Сначала:
"{id:1,type:increase}" //Уменьшить респект пользователю id=1

Затем:

"{id:1,type:increase}" //Увеличить респект пользователю id=1
  1. Допустим есть две копии скрипта обработчика, которые обрабатывают два этих запроса соответственно. Будем называть их script1 и script2
  2. Из-за того, что запросы отправлялись почти одновременно, данные ниже действия выполнялись в следующей последовательности:
4.1 Выполняется строка 6 script1, в которой идет проверка respect пользователя и равна она 101
4.2 Выполняется строка 6 script2, в которой идет проверка respect пользователя и равна она все ещё 101, так как строка 14 script1 еще не выполнилась
4.3 В строке 12 script1 полученное в строке 4 значение(101) уменьшается на 10 и будет равно 91
4.4 В строке 10 script2 полученное в строке 4 значение(101) увеличивается на 10 и будет равно 111
4.5 Сохраняется значение 91 в строке 14 в скрипте script1
4.6 Сохраняется значение 111 в строке 14 в скрипте script2

Полученный в итоге результат равен 111, хотя после понижения на 10 в результате первого запроса, он должен был увеличиться на 5(как сказано в условии задачи). 101-10+5 = 96. Получаем конфликт данных из-за того, что мы проверили значение respect во время обработки второго запроса до того, как оно было изменено уже запущенным первым скриптом-обработчиком первого запроса.

Я постарался на простом примере описать реальную проблему, с которой столкнулся при разработке системы бронирования билетов на мероприятия. Буду рад любым рассуждениям и решениям


Ответы (0 шт):