Возникла необходимость вызывать одну и туже хранимую процедуру MYSQL из разных процессов. И невольно задумался о синхронизации средствами самой СУБД. Вот, что я раскопал:
Стандартные LOCK_TABLE() внутри хранимых процедур вызывать нельзя.
Транзакции (START TRANSACTION) сами блокировки не ставят, так что просто создать innodb таблицу не поможет =)
Есть такой вариант : SELECT ... FOR UPDATE. Он блокирует только строки, которые прочитал до дальнейшего UPDATE. Этот UPDATE должен быть в пределах этой же транзакции, иначе будут проблемы (блокировка не снимется, насколько я понял)
Подошедший мне вариант был такой: GET_LOCK(name, timeout) и RELEASE_LOCK(name).
Работает это все по принципу мутексов. Успешная блокировка возвращает 1, т.е.
SELECT SET_LOCK("my_lock", 10);
-> 1
Если вернулся 0 - значит заблокировал кто-то другой и таймаут истек. А если вообще NULL - то произошла ошибка.
name - задается строкой.
SELECT RELEASE_LOCK("my_lock") вернет 1, если успешно снял блокировку, 0 - если не смог, потому что ее выставил другой поток и NULL - если такой блокировки нет (например, уже сняли, или таймаут истек.)
Для работы с RELEASE_LOCK неплохо подходит оператор DO
DO RELEASE_LOCK("my_lock");
В отличие от SELECT он просто не вернет результат который очень часто от RELEASE и не требуется.
Проверить наличие блокировок можно функциями IS_FREE_LOCK(name) и IS_USED_LOCK(name).
Принцип возврата - такой же. 1 - если ответ "да", 0 - если "нет" и NULL - если такой блокировки вообще не найдено.
Источник информации - документация :)
Стандартные LOCK_TABLE() внутри хранимых процедур вызывать нельзя.
Транзакции (START TRANSACTION) сами блокировки не ставят, так что просто создать innodb таблицу не поможет =)
Есть такой вариант : SELECT ... FOR UPDATE. Он блокирует только строки, которые прочитал до дальнейшего UPDATE. Этот UPDATE должен быть в пределах этой же транзакции, иначе будут проблемы (блокировка не снимется, насколько я понял)
Подошедший мне вариант был такой: GET_LOCK(name, timeout) и RELEASE_LOCK(name).
Работает это все по принципу мутексов. Успешная блокировка возвращает 1, т.е.
SELECT SET_LOCK("my_lock", 10);
-> 1
Если вернулся 0 - значит заблокировал кто-то другой и таймаут истек. А если вообще NULL - то произошла ошибка.
name - задается строкой.
SELECT RELEASE_LOCK("my_lock") вернет 1, если успешно снял блокировку, 0 - если не смог, потому что ее выставил другой поток и NULL - если такой блокировки нет (например, уже сняли, или таймаут истек.)
Для работы с RELEASE_LOCK неплохо подходит оператор DO
DO RELEASE_LOCK("my_lock");
В отличие от SELECT он просто не вернет результат который очень часто от RELEASE и не требуется.
Проверить наличие блокировок можно функциями IS_FREE_LOCK(name) и IS_USED_LOCK(name).
Принцип возврата - такой же. 1 - если ответ "да", 0 - если "нет" и NULL - если такой блокировки вообще не найдено.
Источник информации - документация :)
Комментариев нет:
Отправить комментарий