2013-11-20 5 views
6

Я заперли одну строку в одной транзакции с помощью следующего запросаВыберите только разблокированные строки MySQL

START TRANSACTION; 

SELECT id FROM children WHERE id=100 FOR UPDATE; 

А в другой транзакции, у меня есть запрос, как показано ниже

START TRANSACTION; 

SELECT id FROM children WHERE id IN (98,99,100) FOR UPDATE; 

Это дает стопорное ошибка ожидания ожидания превышено ,

Здесь 100 уже заблокировано (в первой транзакции) Но идентификаторы 98,99 не заблокированы. Есть ли какая-либо возможность вернуть записи 98,99, если только 100 заблокировано строкой в ​​вышеуказанном запросе. Результат должен быть следующим:

Id

===

===

Идентификатор 100 должен игнорироваться, поскольку 100 заблокирована транзакцией.

+0

Вы используете InnoDB для блокировки таблицы строк? –

+0

Да, я использую InnoDB –

ответ

5

MySQL не есть способ, чтобы игнорировать заблокированные строки в SELECT. Вам нужно будет найти другой способ отложить строку в сторону как «уже обработанную».

Простейший способ заключается в том, чтобы коротко зафиксировать строку в первом запросе только для того, чтобы пометить ее как «уже обработанную», затем разблокировать ее и снова заблокировать для остальной части обработки - второй запрос будет ждать короткого замыкания », маркер "для завершения, и вы можете добавить явное условие WHERE, чтобы игнорировать уже отмеченные строки. Если вы не хотите полагаться на первую успешную операцию, вам может потребоваться добавить немного сложнее с отметками времени и таким образом очистить после этих неудачных операций.

+1

Одна из проблем заключается в том, что между маркировкой ее как «уже обработанной» и разблокировкой, а затем блокировкой для фактической обработки процесс может завершиться неудачно, и теперь у нас есть строка, которая помечена как «уже обработанная», но ничто ее не обработало. – CMCDragonkai

+0

@CMCDragonkai Да, это становится очень сложным, когда учитываются различные режимы отказа. Чтобы решить конкретную проблему, которую вы упомянули, строка может быть первоначально отмечена «обработкой» временной меткой, и другой процесс может прийти и снять отметку с любых строк, которые слишком долго были помечены как «обработка». – Brilliand

0

В соответствии с http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

Решение состоит в том, чтобы выполнить SELECT в режиме с использованием стопорного LOCK IN SHARE MODE:

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE; 
+1

В моем случае режим блокировки в режиме общего доступа возвращает все 3 строки (см. Мой второй запрос), но мне нужно всего 2 строки, которые не заблокированы. Строка из строки не должна быть возвращена; –

+1

Вы думаете о результатах фильтрации на основе идентификатора, который вы получаете при первом вызове? Вы можете найти дополнительную информацию в http://bugs.mysql.com/bug.php?id=49763 –

1

У MySQL нет этой функции. Для тех, кто ищет эту тему в целом, некоторые РСУБД имеют лучшие/умные функции блокировки, чем другие.

Для разработчиков, ограниченных MySQL, наилучшим подходом является добавление столбца (или использование существующего, например, столбца состояния), который может быть установлен на «заблокирован» или «в процессе» или аналогичный, выполните SELECT ID, * ... WHERE IN_PROGRESS != 1 FOR UPDATE;, чтобы получить идентификатор строки, который вы хотите заблокировать, введите UPDATE .. SET IN_PROGRESS = 1 WHERE ID = XX, чтобы разблокировать записи.

Использование LOCK IN SHARE MODE почти никогда не является решением, потому что пока оно позволит вам прочитать старое значение, но старое значение находится в процессе обновления, поэтому, если вы выполняете неатомную задачу, нет смысла даже в том, глядя на эту запись.

Лучше * RDBMS распознает этот шаблон (выберите одну строку, чтобы работать и блокировать ее, работать над ней, разблокировать ее) и обеспечить более разумный подход, который позволяет вам искать только разблокированные записи. Например, PostgreSQL 9.5+ предоставляет SELECT ... SKIP LOCKED, который выбирает только из разблокированного подмножества строк, соответствующих запросу. Это позволяет вам получить эксклюзивную блокировку в строке, службу, которая завершает запись, а затем обновить &, разблокировать эту запись, не блокируя другие потоки/потребители от возможности работать независимо от себя.

* Здесь «лучше» означает с точки зрения атомных обновлений, многопользовательской архитектуры и т. Д. И не обязательно «лучше разработан» или «лучше». Не пытаясь начать огонь здесь.

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