2013-03-17 3 views
0

Мой вопрос похож на: Ignoring locked row in a MySQL query за исключением того, что я уже реализовал логику, близкую к тому, что предложено в принятом ответе. Мой вопрос - как установить идентификатор процесса изначально. Все сервера выполнить запрос, как (код в рубине на рельсах, но в результате MySQL запрос):Пропустить заблокированные строки в обновлении mysql, чтобы избежать таймаута блокировки

UPDATE (some_table) SET process_id=(some process_id) WHERE (some condition on row_1) AND process_id is null ORDER BY (row_1) LIMIT 100 

Теперь то, что происходит, все процессы пытаются обновить одни и те же строки, что они заперты, и они тайм-аут в ожидании замок. Я хотел бы, чтобы серверы игнорировали строки, которые заблокированы (потому что после освобождения блокировки process_id не будет больше нуля, так что здесь нет смысла блокировать). Я мог бы попытаться рандомизировать пакет записей для обновления, но проблема в том, что я хочу расставить приоритеты для обновления на основе row_1, как в приведенном выше вопросе. Итак, мой вопрос: есть ли способ в mysql проверить, заблокирована ли запись, и игнорировать ее, если она есть?

ответ

0

Нет, нельзя игнорировать уже заблокированные строки. Ваш лучший выбор будет заключаться в том, чтобы ничто не блокировало любую строку в течение длительного периода времени. Это гарантирует, что любые конфликты блокировок очень короткие по продолжительности. Это обычно означает «консультативную» блокировку строк путем блокировки их в транзакции (с использованием FOR UPDATE) и обновления строки, чтобы отметить ее как «заблокированную».

Например, сначала вы хотите найти свой кандидат строку (ы) без ничего блокировки:

SELECT id FROM t WHERE lock_expires IS NULL AND lock_holder IS NULL <some other conditions>; 

Теперь блокировки только строку, которую вы хотите, очень быстро:

START TRANSACTION; 
SELECT * FROM t WHERE id = <id> AND lock_expires IS NULL AND lock_holder IS NULL; 
UPDATE t SET lock_expires = <some time>, lock_holder = <me> WHERE id = <id>; 
COMMIT; 

(Техническое примечание: если вы планируете блокировать несколько строк, всегда блокируйте их в определенном порядке. По возрастанию по первичному ключу - это достойный выбор. Блокировка вне порядка или в случайном порядке подвергает вашу программу взаимоблокировкам от конкурирующих процессов.)

Теперь вы можете взять столько, сколько хотите (меньше lock_expires), чтобы обрабатывать строки, не блокируя какой-либо другой процесс (они не будут соответствовать строке во время неблокирующего выбора, поэтому всегда будут игнорировать ее). После обработки строки вы можете UPDATE или DELETE его id, также не блокируя ничего.

+0

Мне интересно, если состояние изменилось между этими вызовами. Это будет происходить довольно часто в реальном мире. – gelmanet

Смежные вопросы