Как намеренно заблокировать строку MySQL, чтобы даже SELECT возвращал ошибку?
Я пытаюсь использовать блокировку строк MySQL, чтобы в основном эмулировать MuteEx для строки. Допустим, моя таблица имеет 2 столбца, идентификатор и текстовое поле, а также три записи (1,a) (2,b) и (3,c). SELECT * FROM table; вернул бы эти результаты. Я могу заблокировать определенную строку обычным способом.
START TRANSACTION;
BEGIN;
SELECT * FROM table WHERE id = '2' FOR UPDATE;
Однако, если со второго соединения я должен был выбрать * из таблицы. Это вернуло бы все 3 результата. Есть ли способ для блокировки на уровне строк, чтобы в принципе запретить любому SELECT видеть / использовать заблокированную строку? По сути, я пытаюсь помешать кому-либо использовать строку, которая в настоящее время используется / манипулируется, или даже просматривать строку как ее данные (поскольку она используется / манипулируется), нельзя доверять, чтобы быть точной во время SELECT,
4 ответа
Если вы установите уровень изоляции транзакции на SERIALIZABLE
, InnoDB
придет бесчестье LOCK IN SHARE MODE
все SELECT
заявления.
Этот режим конфликтует с блокировками, установленными SELECT FOR UPDATE
и SELECT
s заблокируется.
Обратите внимание, что InnoDB
может заблокировать больше строк, чем удовлетворяет WHERE
состояние. Это происходит потому, что он блокирует все отсканированные строки, а не только совпадающие.
Скажем, у вас есть индекс на col1
и этот запрос:
SELECT *
FROM mytable
WHERE col1 = 1
AND col2 = 2
FOR UPDATE
использует этот индекс.
Это заблокирует все записи с col1 = 1
даже с col2 <> 2
Тебе необходимо LOCK IN SHARE MODE
, Использование его с SELECT гарантирует, что никто не блокирует строки FOR UPDATE
,
например
Клиент А делает SELECT * FROM table WHERE type=2 FOR UPDATE
Клиент Б делает SELECT * FROM table LOCK IN SHARE MODE
и висит здесь
Клиент A пишет /INSERTs/UPDATE, а затем выполняет COMMIT
Клиент B теперь разблокирует и возобновляет обработку
На самом деле, данным строки можно доверять, даже когда вы манипулируете ими.
Если вы начнете транзакцию с одного соединения, другие соединения не увидят никаких ваших изменений, пока вы не совершите транзакцию.
Я не знаю, есть ли собственный, блокирующий механизм для этого, но мой первый инстинкт - дать таблице столбец статуса (например, locked
) и установите это в 1
при блокировке ряда. select
чувствительный к этому, то всегда будет добавлять WHERE locked != '1'
условие для любого запроса.
С другой стороны, я не знаю, что вы делаете, но разве это не задача, которая должна выполняться на один или два уровня выше ядра базы данных?