Intereting Posts
PHP проверяет числовое значение внутри цикла foreach с парами ключей и значений? Как создать pdf-файл из динамических данных, поступающих из базы данных mysql в php? Создание соли в PHP Как обрезать фрагменты HTML без разбивки тегов? Таблица MySQL, заполняющая один dropdown. После выбора, выпадающее второе выселение Использование PHP, как мне сделать правило перезаписи? PHP: отображать содержимое после принудительной загрузки? преобразование текста в int из формы Может ли система авторизации Laravel использовать существующую базу данных? проблема с знаком «&» при использовании ajax для отправки данных на php Как читать карту в веб-приложении php, написанном с использованием Boost C ++ (в общей области)? Как я могу общаться между PHP и Java-программой? Doctrine2 bulk import пытается работать с другим объектом PHP: Как определить, содержит ли строка какие-либо специальные символы? Как работает PHP-память

Предотвращение одновременных транзакций в веб-приложении

У нас есть веб-приложение (это игра) с множеством различных форм и элементов, которые действуют как кнопки и запускают некоторые действия на сервере. Проблема в том, что пользователи иногда могут путать наше приложение, если он нажимает на кнопки слишком быстро или открывает веб-сайт на двух вкладках, а затем выдает некоторые действия одновременно. У нас есть некоторая базовая защита – транзакции MySQL, некоторые двойные щелчки, предотвращающие Javascripts, но в любом случае иногда что-то просто проскакивает. Конечно, лучшим способом было бы перепроектировать все транзакции SQL и поддерживающие функции таким образом, чтобы не путать систему. Одним из примеров такой путаницы является одновременное выдача двух обновлений – один веб-запрос что-то изменяет в db, но второй запрос все еще работает со старыми данными, поэтому SQL-обновление возвращает «количество затронутых строк равно нулю», потому что первая транзакция уже изменилась данные в дБ. Очевидным решением является считывание данных еще раз перед UPDATE, чтобы узнать, нуждается ли он в обновлении, но это означает, что во многих случаях нужно делать более двойные запросы SELECT, а не хорошее решение – зачем читать одни и те же данные из db дважды? Также мы рассмотрели использование скрытого токена для сравнения на сервере по каждому запросу обновления и отказали в операциях, имеющих одинаковый идентификатор маркера, но это также означает касание действительно многих мест кода и, возможно, введение новых ошибок в систему, которая работает просто отлично, кроме это одна проблема.

Логика потока действий будет следующей: если пользователь выдал два запроса одновременно, второй запрос должен дождаться завершения первого. Но мы также должны учитывать, что в нашем приложении много перенаправлений (например, после POST, чтобы избежать двойной POST, когда пользователь обновляет страницу), поэтому решение не должно создавать взаимоблокировки для пользователя.

Итак, вопрос в том, что было бы самым простым глобальным решением, которое могло бы как-то сделать все пользовательские операции последовательными? Есть ли хорошее универсальное решение?

Мы используем MySQL и PHP.

    Я рад, что вы понимаете, что это только плохое и временное решение, и вы должны оптимизировать свой код. Забудьте свои жетоны и прочее. Самый простой и по-прежнему эффективный способ – это, вероятно, иметь исключительную блокировку файлов для общего файла за операцию. Вы можете представить это как кусок дерева, и только один может содержать идентификатор, и только тот, кто держит его, может говорить или что-то делать.

    <?php $fp = fopen("/tmp/only-one-bed-available.txt", "w+"); if (flock($fp, LOCK_EX)) { // do an exclusive lock // do some very important critical stuff here which must not be interrupted: // sleeping. sleep(60); echo "I now slept 60 seconds"; flock($fp, LOCK_UN); // release the lock } else { echo "Couldn't get the lock!"; } fclose($fp); ?> 

    Если вы выполняете этот скрипт 10 раз параллельно, это займет 10 минут (потому что есть только одна кровать!), И вы увидите эхо «Я сейчас спал …» каждые 60 секунд (приблизительно).

    Это сериализует ВСЕ исполнение этого кода GLOBALY. Это, вероятно, не то, что вы хотите (вы хотите, чтобы он был на основе каждого пользователя, не так ли?) Я уверен, что у вас есть что-то вроде идентификаторов пользователей, в противном случае используется чужой IP-адрес и есть уникальное имя файла для каждого пользователя :

    <?php $fp = fopen("/tmp/lock-".$_SERVER["REMOTE_ADDR"].".txt", "w+"); ?>

    Вы также можете определить имя файла блокировки для группы операций. Maby пользователь может делать некоторые вещи параллельно, но только эта операция создает проблемы? Дайте ему тег и включите его, чтобы он заблокировал имя файла!

    Эта практика действительно не так уж плоха и может быть использована! Есть только немного способов сделать это быстрее (внутренности mysql, сегменты разделяемой памяти, сериализация на более высоком уровне, таком как балансировка нагрузки …)

    С решением, размещенным выше, вы можете сделать это в своем приложении, что, вероятно, хорошо. Вы можете использовать ту же схему в Mysql: http://dev.mysql.com/doc/refman/5.0/ru/miscellaneous-functions.html#function_get -lock

    Но реализация PHP, вероятно, проще и лучше для вашего использования.

    Если вы действительно хотите поднять задницу еще более элегантным решением, просто проверьте эту функцию http://www.php.net/manual/en/function.sem-get.php

    Две вкладки и одновременное действие? Как быстро ваши пользователи?

    Во всяком случае: разрешение только одной вкладки уже будет хорошим решением.

    Имея только одну вкладку, вы можете складывать действия в javascript и отправлять новую, когда у вас есть возвращаемое значение, которое формирует последний вызов.

    Как насчет использования функции get_lock mysql? Также, возможно, вам стоит взглянуть на транзакции mysql.