Блокировка уровня строки в Mysql

У меня есть 5 строк в таблице (от 1 до 5). Я хочу заблокировать строку 2 для какого-то обновления, и в то же время, если кто-то пытается обновить строку 4, то он должен иметь возможность обновить.

Я пытаюсь это с кодом ниже, но я чувствую, что его блокировка размещения на уровне таблицы, а не на уровне строки.

------ сессия 1

START TRANSACTION;
SELECT * FROM test WHERE t=1 FOR UPDATE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;

----- сессия 2 (которая блокируется)

START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;

2 ответа

Вместо FOR UPDATE использование LOCK IN SHARE MODE, FOR UPDATE предотвращает чтение строк другими транзакциями. LOCK IN SHARE MODE позволяет читать, но предотвращает обновление.

Ссылка: руководство по MySQL

------ сессия 1

START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;

----- сессия 2 (которая больше не блокируется:))

START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;

Обновить:

Понимая, что таблица не имеет индекса на tУ меня есть следующее объяснение:

Во-первых, транзакция T1 блокирует строку 1 в SELECT * FROM test WHERE t=1 FOR UPDATE

Затем транзакция T2 пытается выполнить UPDATE test SET NAME='irfandd' WHERE t=4, Чтобы выяснить, какие строки затронуты, необходимо просканировать все строки, включая строку 1. Но это заблокировано, поэтому T2 должен дождаться окончания T1. Если есть какой-либо индекс, WHERE t=4 можно использовать индекс, чтобы решить, содержит ли строка 1 t=4 или нет, так что ждать не нужно.

Вариант 1: добавить индекс на test.t так что ваше обновление может использовать его.

Вариант 2: использовать LOCK IN SHARE MODE, который предназначен только для установки блокировки чтения. К сожалению, эта опция создает тупик. Интересно, что транзакция T2 выполняется (обновление строки 4), а T1 - неудача (обновление строки 2). Кажется, что T1 также блокирует чтение строки 4, и, поскольку T2 модифицирует ее, T1 завершается сбоем из-за уровня изоляции транзакции ( по умолчанию REPEATABLE READ). Окончательное решение будет играть с уровнями изоляции транзакций, используя READ UNCOMMITTED или же READ COMMITTED уровни транзакций.

Самый простой вариант 1, ИМХО, но это зависит от ваших возможностей.

Я нашел ниже вариант более подходящим, я генерирую 40000 номеров из одновременной сессии в одно и то же время. Я не нашел дубликатов. Без приведенной ниже команды я сгенерировал 10000 номеров и нашел 5 дубликатов.

НАЧАТЬ СДЕЛКУ

ВЫБЕРИТЕ * ИЗ ТЕСТА, ГДЕ t=1 ДЛЯ ОБНОВЛЕНИЯ;

ОБНОВЛЕНИЕ теста SET NAME = 'irfandd' WHERE t = 2;

COMMIT;

Другие вопросы по тегам