Как правильно блокировать записи в MySQL?
Есть таблица с данными. Приложение в многопоточном режиме обращается в таблице и берет строки из нее для обработки, после обработки строка должна быть обновлена.
- Как избежать того что 2 потока возьмут в работу одну и ту же строку?
- Что будет если приложение прервется с ошибкой во время обработки строк? Взятые в работу строки будут заблокированы СУБД? Как избежать проблем с этим на случай вылета приложения?
Ответы (1 шт):
Используйте SELECT ... FOR UPDATE SKIP LOCKED. В транзакции делайте запрос типа такого, чтоб выбрать какое-то количество записей для обработки
SELECT *
FROM job_queue FOR UPDATE SKIP LOCKED
ORDER BY some_field
LIMIT <batch_size>
Обработав записи делайте обычный UPDATE записей которые выбрал запрос ранее, ну там помечайте статус, что они уже обработаны или вообще удаляйте их (главное чтоб новый SELECT запрос их не получал), и фиксируйте транзакцию (делайте commit).
Тут SKIP LOCKED как раз избегает проблемы #1, т.е. того, что два обработчика возьмут одну и ту же запись.
Если приложение прервется с ошибкой, то транзакция автоматически откатится базой данных и все заблокированные записи освободятся, и другие обработчики смогут их взять в обработку.