У меня есть странная проблема (по крайней мере, для меня :)) со средством блокировки MySQL.
У меня есть таблица:
create table `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1
С этими данными:
+----+
| идентификатор |
+----+
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 10 |
| 11 |
| 12 |
+----+
Теперь у меня есть 2 клиента с этими командами, выполняемыми вначале:
набор autocommit=0;
сериализуемый уровень изоляции транзакции сессии набора;
начните;
Теперь самая интересная часть. Первый клиент выполняет этот запрос: (делает намерение вставить строку с идентификатором, равным 9),
ВЫБЕРИТЕ * из теста где идентификатор = 9 FOR UPDATE;
Пустое множество (0,00 секунды)
Затем второй клиент делает то же:
ВЫБЕРИТЕ * из теста где идентификатор = 9 FOR UPDATE;
Пустое множество (0,00 секунды)
Мой вопрос: Почему второй клиент не блокируется? Эксклюзивная блокировка разрыва должна была быть установлена первым запросом, потому что FOR UPDATE использовался, и второй клиент должен заблокироваться.
Если я неправ, кто-то мог бы сказать мне, как сделать это правильно?
Версия MySql, которую я использую: 5.1.37-1ubuntu5.1
Потому что в это время безопасно возвращать (пустой) результат - re не устанавливает блокировку для записи с id = 9, поскольку она не существует и, следовательно, не может быть обновлена - я не думаю, что вы можете полагаться на innodb, устанавливающий блокировки чтения в таком случае. Однако он должен установить блокировку записи на id = 9.
Если позже одна из транзакций действительно обновит таблицу и коснется тех же данных, что и другая транзакция, обновление, скорее всего, заблокирует одну из транзакций, а затем потерпит неудачу, если другая транзакция зафиксирует эти данные. Совершенно нормально, что транзакции терпят неудачу в подобных сценариях - оставляя вас заниматься этим - обычно это вопрос повторной попытки транзакции.
Если бы существовала запись с id = 9, вы, вероятно, увидели бы блок 2. select
до завершения первой транзакции, так как теперь есть запись, которую необходимо заблокировать для чтения в случае, если первая транзакция решает обновить эту строку.