Является ли потокобезопасность реальной проблемой в PHP 5.4?
Возможно ли в моем приложении PHP 5.4.0 (IIS, FastCGI, не потокобезопасном), чтобы два человека обновляли одну и ту же таблицу в базе данных, выполняя один и тот же код в одно и то же время и непреднамеренно путали данные друг друга?
Причина, по которой я спрашиваю, заключается в том, что я вижу случайные необъяснимые сбои в данных, и в последнем случае я обнаружил, что другой клиент обновил ту же таблицу точно в то же время.
И вторая часть моего вопроса заключается в том, действительно ли это происходит, как мне это предотвратить?
2 answers
Они не могут "испортить данные друг друга" из-за не потокобезопасного PHP, нет, если вы не готовите/не записываете настройки Apache (например, с помощью SetLocale
) или вы запрограммировали его для одновременного обновления общей информации (например, плоские файлы, как говорит Амадам).
Большинство обычных процессов, таких как MySQL, чтение параметров GET и т.д., Не будут затронуты.
Поэтому, если у вас нет проблем с локализациями, это будет ваш код, а не настройки потока.
Если это с SetLocale, то транзакции или другие методы не будут иметь никакого значения. Во всяком случае, еще вы можете запрограммировать раунд.
Вы можете испортить данные, если не запрограммировали одновременные действия - это может произойти как в потокобезопасном, так и в не потокобезопасном режиме. Помните, что даже в "потокобезопасном" у вас могут быть параллельные потоки, обрабатываемые с разной скоростью и порядками.
Вот опасный пример:
- Инструкция a) Прочитайте таблицу, чтобы получить следующее значение обновления
- Инструкция б) Запись в таблицу с помощью предыдущее значение
- Инструкция c) Обновите таблицу "следующее обновление" для следующего пользователя.
Инструкции могут быть обработаны "Пользователем 1", выполняющим все, за которым следует "Пользователь 2" (идеально, и как вы его запрограммировали). Но в равной степени "Пользователь 1" запускает "a" и "b", затем "Пользователь 2" запускает все, затем "Пользователь 1" запускает "c" - в этом случае "Пользователь 2" перезапишет то, что написал "Пользователь 1".
(Повторяю, это НЕ имеет НИЧЕГО общего с "не потокобезопасностью" в PHP.)
Как обойти это последнее проблема:
- Транзакции МОГУТ вам помочь; на самом деле они не помогут в приведенном выше примере, если вы не используете опцию "С СОГЛАСОВАННЫМ СНИМКОМ", поскольку все, что они делают, это задерживают фиксацию, и вы слишком рано прочитали значение в операторе "a".
- Блокировки таблиц позволяют запретить пользователям чтение или запись в таблицу, поэтому в приведенном выше примере сначала заблокируйте таблицу "обновить", запустите транзакции, а затем снимите блокировку. Это заставляет второго пользователя ждать, пока "Пользователь 1" завершил лот до того, как прочитал номер.
- Используйте возможности MySQL, включая "АВТОМАТИЧЕСКОЕ УВЕЛИЧЕНИЕ" первичных ключей или кодов, таких как "ВСТАВИТЬ В... НА ДУБЛИРУЮЩЕМ КЛЮЧЕ" или "ЗАМЕНИТЬ".
Третий вариант - лучший, если вы можете. Блокировки таблиц могут привести к беспорядку, и транзакции не решат ваши проблемы.
Если вы выполняете более одного оператора SQL в каждом запросе без использования транзакций, то это очень возможно. Операторы SQL являются атомарными, как и последовательность операторов, завернутая в транзакцию, поэтому не должно быть никаких "сбоев".
Кроме того, если вы разделяете состояние между различными запросами в любом месте, кроме SQL (например, плоские файлы), очевидно, что безопасность потоков будет, по меньшей мере, нарушена.
Часть вторая: используйте транзакции:)