критический раздел в php между всеми запросами - PullRequest
3 голосов
/ 19 октября 2011

Я делаю сайт на php, на котором я хочу продать несколько платных номеров.Для каждого запроса я должен выполнять следующие операции:

  • Запрашивать в базе данных доступный номер заряда
  • , отмечая номер заряда как проданный
  • , увеличиваячисло (в файле или базе данных), которое показывает количество клиентов, получивших номер платежа

Я знаю, как выполнять эти операции, и если это может помочь, я использую mysql.Но моя проблема в том, как сделать эти операции атомарными между всеми запросами?Я имею в виду, как я могу заставить веб-сервер (apache) и интерпретатор php запускать эту часть один за другим для всех запросов, а не параллельно?

Ps: Пожалуйста, сделайте ваши ответы как решение php, а не решение, связанное с базой данных.

Ответы [ 3 ]

5 голосов
/ 19 октября 2011

Недостатком использования php-ориентированного решения является то, что вы можете гарантировать это только на одной машине.Конечно, вы можете заблокировать его для одного процесса в критической области, но только на одной машине.Если бы у вас было 2 внешних сервера Apache / php и один внутренний сервер MySQL, это решение не сработало бы.Транзакция MySQL - безусловно, лучшее решениена сервере linux / unix вы также можете использовать методы IPC и создать семафор system V длиной 1 (мьютекс).

# in your scripts setup/init phase:
define('MUTEX_KEY', 123456); # the key to access you unique semaphore
sem_get( MUTEX_KEY, 1, 0666, 1 );
# later on, you reach the critical section:
# sem_acquire will block until the mutex has become availible
sem_acquire( ($resource = sem_get( MUTEX_KEY )) );
# queries here ...
sem_release( $resource );
# now that sem_release has been called, the next processes that was blocked
# on the sem_acquire call may enter the critical region

Хотя решение на основе файлов более переносимо (работает на серверах Windows)решение mutex / sem_ * намного быстрее и безопаснее (auto_release, например, если приложение по какой-либо причине падает в критической области, не блокирует все дальнейшие запросы)

Cheers

5 голосов
/ 19 октября 2011

Все эти операции действительно зависят от базы данных. Так что вам не нужно заставлять PHP запускать код в критической секции; достаточно сериализовать эти операции в базе данных.

Самый простой способ сделать это - LOCK TABLES ... WRITE во время выполнения этих действий; это гарантирует, что только один сценарий будет одновременно взаимодействовать с базой данных.

Другой подход заключается в SET TRANSACTION ISOLATION LEVEL SERIALIZABLE и запуске всех операций в транзакции с отключенной автоматической фиксацией (вы должны действительно использовать транзакцию для обеспечения целостности данных, даже если вы решите использовать блокировку таблицы, хотя ).

Обновление: Если вам абсолютно необходимо сделать это в PHP, вы можете достичь цели, используя flock:

$fp = fopen('sunc_file', 'r+');
if (flock($fp, LOCK_EX)) {
    // Perform database ops here
    flock($fp, LOCK_UN); // release the lock
}
else {
    die("Couldn't get the lock!");
}
fclose($fp);

flock в эксклюзивном режиме предотвратит блокировку файла защиты любым другим процессом и, таким образом, позволит вашим сценариям выполняться строго сериализованно, , но, пожалуйста, прочитайте гигантские красные предупреждения на странице man !

0 голосов
/ 20 августа 2013

Вот пример кода для критической секции http://www.bogan.cz/programovani/kriticka-sekce-v-php/. Поиск секции кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...