Поделитесь опытом успешного использования и проблем, возникающих в связи с использованием.
Лично я сегодня наткнулся на то, что мне ко всем чертям заблочило почти всю таблицу, несмотря на то, что я делаю 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
Код написан так, что бы не держать блокировку дольше нескольких миллисекунд и конкретно эта часть не отваливается. Бывало отваливались другие части и по какой-то мне не понятной причине оказалось что почти все записи в таблице залочились, хотя такого происходить не должно.
Инфы толком нарыть в и-нете пока не получилось о багах и особенностях, пока продолжаю копать.
Т.е. есть только такого типа запросы?
«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 держит. „
Нет, там по другому работает. SELECT FOR UPDATE блокирует в эксклюзивную блокировку те строки, что он выбрал, а при UPDATE этой строки он блокировку снимает. Транзакции там не нужны. Движок конечно InnoDB :)
Вы вообще в курсе, как работает SELECT FOR UPDATE?
На всякий случай:
Locks set by LOCK IN SHARE MODE and FOR UPDATE reads are released when the transaction is committed or rolled back.
Note
Locking of rows for update using SELECT FOR UPDATE only applies when autocommit is disabled (either by beginning transaction with START TRANSACTION or by setting autocommit to 0. If autocommit is enabled, the rows matching the specification are not locked.
>UPDATE WHERE id = $id
Зачем здесь where? Если 2 отдельных where то нет ли вероятности, что оно просто апдейтило не связанные с SELECT FOR UPDATE варианты?
Тоже недавно столкнулся с проблемой конкуретного доступа на запись, в моем случае я буду реализовывать это следующим способом — у каждого процесса, который будет работать с таблицей будет свой ИД, к таблице добавлю поле «busy» по умолчанию будет равно 0. Далее каждый процесс будет выполнять следующее
UPDATE tbl SET busy=$ИД WHERE id=(SELECT max(id) FROM tbl WHERE busy=0)
и дальше будет делать все что угодно с этой записью.
MySQL не разрешает в под-запросе делать Select из таблицы, которой делается Update в основном запросе. Но есть костыль. Тоже думал так сделать, пока ещё не пробовал. Надеюсь на вменяемое решение…
Та же ситуация! FOR UPDATE реально спасает. Записи выбираются как надо и не возникает race-condition. Но стоит запустить другой долгий запрос, который обращается к этой таблице(у меня JOIN), как тут-же все запросы начинают возвращать конкурентно одни и те же записи. Всё ещё пытаюсь найти решение…
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));
Есть база данных mysql, в ней находится таблица — абоненты.
Есть несколько операторов которые звонят этим абонентам, как мне сделать так, чтобы каждому оператору выдавались абоненты и чтоб операторам не попадались одинаковые абоненты? В систему они заходят параллельно.