У меня есть одна таблица, которая одновременно читается разными потоками.
Каждый поток должен выбрать 100 строк, выполнить некоторые задачи в каждой строке (не связанные с базой данных), затем они должны удалить выбранную строку из таблицы.
строки выбираются с помощью этого запроса:
SELECT id FROM table_name FOR UPDATE;
Мой вопрос: как я могу игнорировать (или пропустить) строки, которые были ранее заблокированы с помощью оператора select в MySQL?
Обычно я создаю столбец process_id со значением NULL по умолчанию, а затем каждый поток использует уникальный идентификатор для выполнения следующих действий:
UPDATE table_name SET process_id = #{process.id} WHERE process_id IS NULL LIMIT 100;
SELECT id FROM table_name WHERE process_id = #{process.id} FOR UPDATE;
Это гарантирует, что каждый поток выбирает уникальный набор строк из таблицы.
Надеюсь это поможет.
Хотя это не лучшее решение, поскольку я не знаю, как игнорировать заблокированные строки, я выбираю случайную и пытаюсь получить блокировку.
START TRANSACTION;
SET @v1 =(SELECT myId FROM tests.table WHERE status is NULL LIMIT 1);
SELECT * FROM tests.table WHERE myId=@v1 FOR UPDATE; #<- lock
Устанавливая небольшой тайм-аут для транзакции, если эта строка заблокирована, транзакция прерывается, и я пробую другую. Если я получу блокировку, я обработаю ее. Если (неудача) эта строка была заблокирована, она обрабатывается, и блокировка снимается до истечения моего тайм-аута, тогда я выбираю строку, которая уже была «обработана»! Однако я проверяю поле, которое установили мои процессы (например, статус): если другая транзакция процесса завершилась нормально, это поле говорит мне, что работа уже выполнена, и я больше не обрабатываю эту строку.
Любое другое возможное решение без транзакций (например, установка другого поля, если строка не имеет статуса и … и т. Д.) Может легко обеспечить условия гонки и пропущенные процессы (например, один поток внезапно умирает, выделенные данные по-прежнему помечены, а транзакция истекает ссылка на комментарий Вот
Надеюсь, поможет