Как сделать один запрос вне зависимости от количества переходов?
У меня есть такой код:
if ( $user_damage > $battle['health'] ) { mysql_query('SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE'); mysql_query('START TRANSACTION'); try { mysql_query('UPDATE `basement_clans` SET `json_key` = JSON_SET(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"', JSON_EXTRACT(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"') + 1), `json_limit` = JSON_SET(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1), `json_medals` = JSON_SET(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1) WHERE `clan` = '.$clan['id'].' AND `jail` = '.$user['reset']); mysql_query('DELETE FROM `_basement_battle` WHERE `id` = '.$battle['id']); mysql_query('COMMIT'); } catch (Exception $e) { mysql_query('ROLLBACK'); } } |
if ( $user_damage > $battle['health'] ) { mysql_query('SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE'); mysql_query('START TRANSACTION'); try { mysql_query('UPDATE `basement_clans` SET `json_key` = JSON_SET(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"', JSON_EXTRACT(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"') + 1), `json_limit` = JSON_SET(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1), `json_medals` = JSON_SET(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1) WHERE `clan` = '.$clan['id'].' AND `jail` = '.$user['reset']); mysql_query('DELETE FROM `_basement_battle` WHERE `id` = '.$battle['id']); mysql_query('COMMIT'); } catch (Exception $e) { mysql_query('ROLLBACK'); } }
проблема: когда одновременно бьют несколько пользователей или более, то засчитывает столько сколько было одновременных ударов
нужно: чтобы был один запрос вне зависимости от того, сколько было этих одновременных ударов
использовала: мемкеш, блокировку запросов, атомарные операции, циклы
ничего не помогает
есть 3 таблицы:
basement_clans (id, clan, json_key, json_limit, json_medals, jail) -- С откуда берутся ключи (с которыми и проблема) ($clanData)
_basement_battle (id, clan_id, boss_id, health, jail, time) -- Само сражение ($battle)
_basement_member (id, user_id, user_health, fight_id, clan_id, boss_id, damage, jail) -- Участники сражения (fight_id -> id) ($member)
Дополнительно:
ну малороятно что кто-то поможет и будет настолкьо экстрасенсом что примеры из чат гпт превратит в нужное вам решение....
Ибо кто бьет куда бьет зачем бьет из этого куска кода вообще непонятно.
Какие запросы куда для чего зачем тоже не понятны.
Вообще ваш SQL сервер впринципе не знает о вашей проблеме а тупо трабатывает те запросы которые к нему приходят, если необходимо делать какието условия то это нужно делать до запросов в базу.
Суть вопроса то в чем на какой стороне, что поисходит.
Или у вас люди внутри SQL сервера живут.... и за пределы SQL - клиента не выходят ?
LEVEL SERIALIZABLE
Простите, а в чём был вопрос?
проблема с прибавкой ключей на следующего босса. То есть у меня всего 100 ключей например и когда пользователь бьет например босса номер 5, а другой(ие) разных, то получается так что добавляется через раз дополнительный ключ на какого-то из этих боссов
Вы реально считаете, что кто-то что-то понял из этого повествования?
В общем, скорее всего обычный race condition. А решается оно пониманием того, где это состояние, поэтому обвешивать блокировками нужно не update. Блокировать БД нужно перед проверкой значения и снимать блокировку после обновления, чтобы предотвратить изменение БД в этот промежуток. А проверку вы нам почему-то не показываете...
Либо решить это без блокировок (что разумеется гораздо лучше), например, вставив проверку значения в UPDATE. Например:
update payments set amount=amount-1 where (amount-1)>=0 |
update payments set amount=amount-1 where (amount-1)>=0
Здесь у всех записей amount уменьшаем на 1, но только в том случае, если результат будет положительным.
Вообще, как вариант вы можете кидать события игры в очередь(rabbitmqbeanstalkdetc) и обрабатывать в отдельном воркере последовательно, храня ключ последнего обработанного события где-нибудь в _basement_battle, а при обработке добавить условие
_basement_battle.last_event != 'event_key_from_params' |
_basement_battle.last_event != 'event_key_from_params'
. Это при условии, что результат запроса сразу не должен отдавать какие-то данные.
А в целом:
- ваш обработчик запроса делает только две вещи - вычисляет подпись события(на основе параметров, которые пришли) и кладёт их в очередь(Рэббит, бинсталк, редис, что-то что вам больше по душе), отдаёт ответ что всё ок.
- из очереди события забирает воркер и вполне последовательно их выполняет(если нужно - кидает событие в вебсокет который слушают игроки). Таким образом, мы избавляемся от параллельной обработки событий и имея подпись события можем решать - уникальное это событие и повторные не нужно обрабатывать или же это новые события и их нужно обработать.
Ответы:
if ($user_damage > $battle['health']) { // Установка блокировки на таблицу `_basement_battle` mysql_query('LOCK TABLES `_basement_battle` WRITE'); try { mysql_query('SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE'); mysql_query('START TRANSACTION'); // Выполнение обновлений mysql_query('UPDATE `basement_clans` SET `json_key` = JSON_SET(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"', JSON_EXTRACT(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"') + 1), `json_limit` = JSON_SET(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1), `json_medals` = JSON_SET(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1) WHERE `clan` = '.$clan['id'].' AND `jail` = '.$user['reset']); mysql_query('DELETE FROM `_basement_battle` WHERE `id` = '.$battle['id']); mysql_query('COMMIT'); } catch (Exception $e) { mysql_query('ROLLBACK'); } finally { // Снятие блокировки после выполнения транзакции mysql_query('UNLOCK TABLES'); } } |
if ($user_damage > $battle['health']) { // Установка блокировки на таблицу `_basement_battle` mysql_query('LOCK TABLES `_basement_battle` WRITE'); try { mysql_query('SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE'); mysql_query('START TRANSACTION'); // Выполнение обновлений mysql_query('UPDATE `basement_clans` SET `json_key` = JSON_SET(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"', JSON_EXTRACT(`json_key`, '$."' . 'key_'.($battle['boss_id'] + 1) . '"') + 1), `json_limit` = JSON_SET(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_limit`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1), `json_medals` = JSON_SET(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"', JSON_EXTRACT(`json_medals`, '$."' . 'boss_'.$battle['boss_id'] . '"') + 1) WHERE `clan` = '.$clan['id'].' AND `jail` = '.$user['reset']); mysql_query('DELETE FROM `_basement_battle` WHERE `id` = '.$battle['id']); mysql_query('COMMIT'); } catch (Exception $e) { mysql_query('ROLLBACK'); } finally { // Снятие блокировки после выполнения транзакции mysql_query('UNLOCK TABLES'); } }
- из 271 ключей превратилось 300
- какой кошмар
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для того чтобы сделать один запрос независимо от количества переходов, можно использовать рекурсивную функцию в PHP. Рекурсия позволяет вызывать функцию из самой себя до тех пор, пока не будет выполнено определенное условие.
Прежде всего, создадим функцию, которая будет делать запрос к серверу. Например, мы будем делать запрос к API с помощью функции file_get_contents(). Затем мы будем проверять ответ сервера и, если в ответе будет ссылка на следующую страницу, вызывать эту же функцию с новым URL. Таким образом, мы сможем получить данные со всех страниц, пока не достигнем конечной.
Пример кода:
function makeRequest($url) { $data = file_get_contents($url); $response = json_decode($data, true); // предположим, что ответ сервера приходит в формате JSON // обработка полученных данных // проверяем, есть ли ссылка на следующую страницу if (isset($response['next_page'])) { // вызываем эту же функцию с новым URL makeRequest($response['next_page']); } } // начальный URL для запроса $startUrl = 'https://api.example.com/data'; makeRequest($startUrl);
В данном примере функция makeRequest() делает запрос к API по указанному URL, затем проверяет ответ и, если есть ссылка на следующую страницу, вызывает сама себя с новым URL. Таким образом, мы можем получить данные со всех страниц, пока не достигнем конечной.
Этот подход позволяет сделать один запрос независимо от количества переходов и получить все необходимые данные.