Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Базы Данных > Выборка одной и той же записи таблицы скриптами,


Автор: Xo6oT 26.6.2007, 21:20
Имеется таблица в базе данных MySQL.
Имеется скрипт на php5.
Скрипт делает следущее - извлекает из таблицы первую запись со статусом, равным 1 ("WHERE status=1").
Затем запоминает информацию, хранящуюся в этой записи (для дальнейшей обработки), в локальных переменных.
И сразу же изменяет статус (status) записи на 2 (UPDATE).

Проблема состоит в следующем - 
одновременно запускается несколько копий этого скрипта (для определенности пусть будет 10).

Так вот, эти копии извлекают ОДНУ И ТУ ЖЕ запись.
Мне нужно, чтобы первый скрипт обратился к таблице, выбрал запись, обработал ее. Второй выбрал следующую запись, третий - третью и т.д.

Если блокировать таблицу (LOCK TABLES), то скрипты, следующие за первым (но отстающие на доли секунды), начинают выдавать ошибку - нет доступа. Это логично, конечно. Но мне не хочется каждый раз перезапускать скрипт только из-за того, что ему не хватило доли секунды, пока блолкировка закончится и он обратится к очередной записи. Громоздить конструкции вроде
Код

$success = false;
while(!$success)
{
try
{
getRecord();
}
catch(Exception $e)
{
continue;
}
$success = true;
}

мне представляется не совсем правильным.

Как посоветуете по-человечески добиться нужного мне эффекта (средствами php, или mysql, или комбинированными)?

Автор: sTa1kEr 26.6.2007, 21:56
Если промежуток между SELECT-ом и UPDATE-ом не большой, то я бы предложил использовать транзакции, но для этого надо для таблицы выбрать движок InnoDB. Делается это достаточно просто, сначала начинаем транзакцию и выполняем запрос SELECT FOR UPDATE
Код

START TRANSACTION;
SELECT * FROM `table` WHERE `status` = 1 FOR UPDATE;

Спокойно сохраняем данные, остальные запросы, которые будут затрагивать эту строку будут спокойно ждать, пока не завершится транзакция. Затем UPDATE и завершаем транзакцию.
Код

UPDATE `table` `status` = 1 WHERE `id` = 123;
COMMIT;

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

Автор: Xo6oT 28.6.2007, 15:07
Увы, данный подход не решает мою проблему.
Если я правильно понимаю, 
Код

SELECT ... FOR UPDATE;

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

Автор: sTa1kEr 28.6.2007, 18:55
Цитата(Xo6oT @  28.6.2007,  15:07 Найти цитируемый пост)
Если я правильно понимаю, 
1: SELECT ... FOR UPDATE;
запрещает UPDAT'ить запись, но не запрещает чтение из нее.

Как раз наоборот. Эта конструкция говорит о том, что SELECT выполняется для полседующего UPDATE, а значит строка блокируется на чтение и запись до тех пор, пока не будет завершена транзакция.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)