Является ли потокобезопасность реальной проблемой в PHP 5.4?


Возможно ли в моем приложении PHP 5.4.0 (IIS, FastCGI, не потокобезопасном), чтобы два человека обновляли одну и ту же таблицу в базе данных, выполняя один и тот же код в одно и то же время и непреднамеренно путали данные друг друга?

Причина, по которой я спрашиваю, заключается в том, что я вижу случайные необъяснимые сбои в данных, и в последнем случае я обнаружил, что другой клиент обновил ту же таблицу точно в то же время.

И вторая часть моего вопроса заключается в том, действительно ли это происходит, как мне это предотвратить?

Author: Vincent, 2012-12-05

2 answers

Они не могут "испортить данные друг друга" из-за не потокобезопасного PHP, нет, если вы не готовите/не записываете настройки Apache (например, с помощью SetLocale) или вы запрограммировали его для одновременного обновления общей информации (например, плоские файлы, как говорит Амадам).

Большинство обычных процессов, таких как MySQL, чтение параметров GET и т.д., Не будут затронуты.

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

Если это с SetLocale, то транзакции или другие методы не будут иметь никакого значения. Во всяком случае, еще вы можете запрограммировать раунд.


Вы можете испортить данные, если не запрограммировали одновременные действия - это может произойти как в потокобезопасном, так и в не потокобезопасном режиме. Помните, что даже в "потокобезопасном" у вас могут быть параллельные потоки, обрабатываемые с разной скоростью и порядками.

Вот опасный пример:

  • Инструкция a) Прочитайте таблицу, чтобы получить следующее значение обновления
  • Инструкция б) Запись в таблицу с помощью предыдущее значение
  • Инструкция c) Обновите таблицу "следующее обновление" для следующего пользователя.

Инструкции могут быть обработаны "Пользователем 1", выполняющим все, за которым следует "Пользователь 2" (идеально, и как вы его запрограммировали). Но в равной степени "Пользователь 1" запускает "a" и "b", затем "Пользователь 2" запускает все, затем "Пользователь 1" запускает "c" - в этом случае "Пользователь 2" перезапишет то, что написал "Пользователь 1".

(Повторяю, это НЕ имеет НИЧЕГО общего с "не потокобезопасностью" в PHP.)

Как обойти это последнее проблема:

  1. Транзакции МОГУТ вам помочь; на самом деле они не помогут в приведенном выше примере, если вы не используете опцию "С СОГЛАСОВАННЫМ СНИМКОМ", поскольку все, что они делают, это задерживают фиксацию, и вы слишком рано прочитали значение в операторе "a".
  2. Блокировки таблиц позволяют запретить пользователям чтение или запись в таблицу, поэтому в приведенном выше примере сначала заблокируйте таблицу "обновить", запустите транзакции, а затем снимите блокировку. Это заставляет второго пользователя ждать, пока "Пользователь 1" завершил лот до того, как прочитал номер.
  3. Используйте возможности MySQL, включая "АВТОМАТИЧЕСКОЕ УВЕЛИЧЕНИЕ" первичных ключей или кодов, таких как "ВСТАВИТЬ В... НА ДУБЛИРУЮЩЕМ КЛЮЧЕ" или "ЗАМЕНИТЬ".

Третий вариант - лучший, если вы можете. Блокировки таблиц могут привести к беспорядку, и транзакции не решат ваши проблемы.

 2
Author: Robbie, 2012-12-05 00:54:47

Если вы выполняете более одного оператора SQL в каждом запросе без использования транзакций, то это очень возможно. Операторы SQL являются атомарными, как и последовательность операторов, завернутая в транзакцию, поэтому не должно быть никаких "сбоев".

Кроме того, если вы разделяете состояние между различными запросами в любом месте, кроме SQL (например, плоские файлы), очевидно, что безопасность потоков будет, по меньшей мере, нарушена.

Часть вторая: используйте транзакции:)

 3
Author: Amadan, 2012-12-05 00:16:29