Как сделать один запрос вне зависимости от количества переходов?

Ссылка скопирована
1 ответ

У меня есть такой код:

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 сервер впринципе не знает о вашей проблеме а тупо трабатывает те запросы которые к нему приходят, если необходимо делать какието условия то это нужно делать до запросов в базу.

  • aleks-th, добавила информации о таблицах и их столбиках, и что за что отвечает
  • Елена Кермояк,

    Суть вопроса то в чем на какой стороне, что поисходит.

    Или у вас люди внутри SQL сервера живут.... и за пределы SQL - клиента не выходят ?

  • Зачем это?

    LEVEL SERIALIZABLE

  • mayton2019, уровень изоляции, еще пробовала REPEATABLE READ
  • aleks-th, проблема с прибавкой ключей на следующего босса. То есть у меня всего 100 ключей например и когда пользователь бьет например босса номер 5, а другой(ие) разных, то получается так что добавляется через раз дополнительный ключ на какого-то из этих боссов
  • Елена Кермояк, под боссами вы имеете ввиду начальников вашей организации, директоров? А у вас их несколько? И ключи - это видимо те, которые завхоз на своём поясе держит? Хотя иногда завхоз ещё функции кадровика выполняет, поэтому он завхоз-кадровик, мда. Но вот битьё пользователями директоров - это вообще экстраординарно! Нет, я не осуждаю, директора - они такие, всякое бывает. Но сначала надо выбить ключ из завхоза, лучше в тот момент, когда он не кадровик, открыть этим ключём какой-нибудь кабинет, и вот таааам...
    Простите, а в чём был вопрос?
  • Для всех одновременных ударов параметры $battle['id'], $battle['boss_id'] и $clan['id'] одинаковые?
  • Елена Кермояк,

    проблема с прибавкой ключей на следующего босса. То есть у меня всего 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, но только в том случае, если результат будет положительным.

  • WitER, да
  • Елена Кермояк, выше вам верно подсказали по поводу race condition, как и варианты его решения. Дополню лишь тем, что вы можете вешать лок как на уровне php, так и на уровне бд(Смотреть тут) используя выше обозначенный набор параметров как ключ - это позволит выполнить только первый прилетевший запрос и отбить остальные в ошибкуожидание завершения предыдущего запроса.
    Вообще, как вариант вы можете кидать события игры в очередь(rabbitmqbeanstalkdetc) и обрабатывать в отдельном воркере последовательно, храня ключ последнего обработанного события где-нибудь в _basement_battle, а при обработке добавить условие
    _basement_battle.last_event != 'event_key_from_params'

    _basement_battle.last_event != 'event_key_from_params'

    . Это при условии, что результат запроса сразу не должен отдавать какие-то данные.

  • WitER, делала так, блокировала на уровне php и mysql innodb, не помогает, добавила еще одно условие кто создавал и всё равно либо больше либо меньше ключей получается
  • Елена Кермояк, как именно делали локи на php и на уровне mysql?
  • WitER, mysql_query('SELECT GET_LOCK('battle_lock', 10)'); и функцию в php flock()
  • Елена Кермояк, ну переведите на очередь
  • WitER, можно небольшой пример?
  • Елена Кермояк, чтобы дать вам подходящий под ваши условия пример - нужно иметь представление, как именно у вас работают события и ответы между клиентами и сервером. Будет не плохо, если расскажете подробнее - тогда можно будет более верное решение найти.

    А в целом:
    - ваш обработчик запроса делает только две вещи - вычисляет подпись события(на основе параметров, которые пришли) и кладёт их в очередь(Рэббит, бинсталк, редис, что-то что вам больше по душе), отдаёт ответ что всё ок.
    - из очереди события забирает воркер и вполне последовательно их выполняет(если нужно - кидает событие в вебсокет который слушают игроки). Таким образом, мы избавляемся от параллельной обработки событий и имея подпись события можем решать - уникальное это событие и повторные не нужно обрабатывать или же это новые события и их нужно обработать.

  • Ответы:

    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
    • какой кошмар
    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Виктор Sys Ответ

    Для того чтобы сделать один запрос независимо от количества переходов, можно использовать рекурсивную функцию в 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);

    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. Таким образом, мы можем получить данные со всех страниц, пока не достигнем конечной.

    Этот подход позволяет сделать один запрос независимо от количества переходов и получить все необходимые данные.

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно