@Psih
Веб разработчик, совладелец Areto Development

MySQL — SELECT FOR UPDATE

Поделитесь опытом успешного использования и проблем, возникающих в связи с использованием.

Лично я сегодня наткнулся на то, что мне ко всем чертям заблочило почти всю таблицу, несмотря на то, что я делаю SELECT id FROM… FOR UPDATE и следующей же операцией UPDATE WHERE id = $id.

Версия MySQL — 5.1.31 на убунте.

А workflow у меня таков:
У меня несколько консольных приложений, которые паралельно забирают из таблицы очереди задачки. Т.е. SELECT id FROM queue LIMIT 1 FOR UPDATE и если запись выбралась, то UPDATE queue SET locked = 1 WHERE id = $id
Код написан так, что бы не держать блокировку дольше нескольких миллисекунд и конкретно эта часть не отваливается. Бывало отваливались другие части и по какой-то мне не понятной причине оказалось что почти все записи в таблице залочились, хотя такого происходить не должно.

Инфы толком нарыть в и-нете пока не получилось о багах и особенностях, пока продолжаю копать.

Зарание спасибо за информацию.
  • Вопрос задан
  • 29921 просмотр
Решения вопроса 1
4dmonster
@4dmonster
Т.е. есть только такого типа запросы?
«begin;
select a.d from a where a.b=c for update;
update a set a.d=a.d+1 where a.b=c;
commit;
Главное чтобы таблица поддерживала транзакции. InnoDb держит. „
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
@Tagire
>UPDATE WHERE id = $id
Зачем здесь where? Если 2 отдельных where то нет ли вероятности, что оно просто апдейтило не связанные с SELECT FOR UPDATE варианты?
Ответ написан
Комментировать
@kolesnevg
Тоже недавно столкнулся с проблемой конкуретного доступа на запись, в моем случае я буду реализовывать это следующим способом — у каждого процесса, который будет работать с таблицей будет свой ИД, к таблице добавлю поле «busy» по умолчанию будет равно 0. Далее каждый процесс будет выполнять следующее
UPDATE tbl SET busy=$ИД WHERE id=(SELECT max(id) FROM tbl WHERE busy=0)
и дальше будет делать все что угодно с этой записью.
Ответ написан
Umkus
@Umkus
Та же ситуация! FOR UPDATE реально спасает. Записи выбираются как надо и не возникает race-condition. Но стоит запустить другой долгий запрос, который обращается к этой таблице(у меня JOIN), как тут-же все запросы начинают возвращать конкурентно одни и те же записи. Всё ещё пытаюсь найти решение…
Ответ написан
Комментировать
@shagguboy
SELECT * FROM table t WHERE t.processed = false AND GET_LOCK(CONCAT('process_', t.id), 0) LIMIT 1;
UPDATE table t SET t.processed = true, operator_id = :current WHERE id = :id;
DO RELEASE_LOCK(CONCAT('process_', :id));
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы