MySQL блокировка строк в запросе на выбор для обновления - PullRequest
5 голосов
/ 11 августа 2011

Итак, я пишу простой сканер веб-сайтов для обслуживания внутренних сайтов. Он будет проходить по каждой ссылке, добавляя новые ссылки по мере их нахождения, отмечая заголовок, теги h1 и т. Д.

Иногда он дублирует заголовки и теги H1, когда в источнике есть только один, когда я проверяю его вручную.

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

Сценарий в основном захватывает страницу, которая не была просканирована, затем, если http-ответ равен 200, он помечает ее как просканированную и обрабатывает то, что ему нужно.

Таким образом, где-то между SELECT и UPDATE другой поток скрипта работает в той же строке, что и SELECTed.

Есть ли способ либо SELECT и UPDATE в том же запросе, либо заблокировать строку, возвращенную в SELECT, чтобы она не могла быть возвращена снова в другом запросе в другом потоке, пока я не закончу с этим?

Посмотрел - http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html и общие вещи ВЫБРАТЬ ОБНОВЛЕНИЕ, но я все еще не уверен.

Редактировать

Я использую что-то вроде этого

START TRANSACTION;
SELECT .. FOR UPDATE;
UPDATE .... ;
COMMIT;

Но это не нравится. Я использую InnoDB для этой таблицы. Я думаю, что это может быть не путь вперед, так как он просто откладывает обработку строки до окончания фиксации, когда я хочу, чтобы он физически не смог снова выбрать строку.

Я рассмотрел это, выполнив SELECT, а затем выполняя ОБНОВЛЕНИЕ, чтобы пометить поле как просканированное до его обработки, но тот факт, что это не является бесшовным, кажется, вызывает проблему. Мне нужен способ плавного выбора и обновления поля или выбора и остановки его повторного выбора, пока я не скажу.

Ответы [ 2 ]

3 голосов
/ 12 августа 2011

Когда вы блокируете строку (посредством выбора для обновления), другая транзакция будет ожидать снятия блокировки, вместо того, чтобы пропустить строку и выбрать следующую.Лучшая стратегия будет иметь столбец флага в таблице (нет, обработка завершена), возможно, с отметкой времени.Хрон берет строку, устанавливает флаг для обработки и начинает обработку страницы.Когда выполняется другой экземпляр сценария, он выбирает строки, которые не находятся в состоянии «обработка».Когда cron заканчивает работу, он обновляет запись еще раз до «завершено»

3 голосов
/ 11 августа 2011

Вы сами ответили на вопрос :). SELECT FOR UPDATE это именно то, что вам нужно, если я правильно понимаю ваш вопрос. Не забудьте отключить автокоммит, запустить транзакцию перед выбором и зафиксировать транзакцию после обновления.

Обновление:

Я думаю, что это будет делать то, что вы хотите:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
SELECT .. FOR UPDATE;
UPDATE .... ;
COMMIT TRANSACTION;
...