1. Классификация замков
Блокировки в innodb делятся на S-блокировки, то есть общие блокировки, и другие X-блокировки, эксклюзивные блокировки, такие как:
Общий замок(и)
select * from supplier where id=5 lock in share mode;
Эксклюзивный замок (X)
select * from supplier where id=5 for update;
Или операторы вставки, удаления, обновления, которые являются эксклюзивными блокировками.
совместимость
Совместимость этих двух замков следующая:
X | S | |
---|---|---|
X | N | N |
S | N | Y |
блокировка намерения
Можно понять, что он принадлежит родительскому узлу блокировки S и блокировки X, то есть, если вы хотите получить блокировку S или блокировку X, вы должны сначала получить блокировку намерения, то есть блокировку IS или IX. , совместимость этих двух типов замков следующая
X | S | IX | IS | |
---|---|---|---|---|
X | N | N | N | N |
S | N | Y | N | Y |
IX | N | N | Y | Y |
IS | N | Y | Y | Y |
Неявный замок
Я тоже пьян, зачем тебе столько концептов заниматься. . Этот тип блокировки можно считать не заблокированным, когда нет конфликта. Блокировка в это время является неявной блокировкой. При возникновении конфликта блокировка будет обновлена до явной блокировки. Давайте проиллюстрируем это на примере:
Транзакция 1 (где возраст — нормальный показатель)select * from test01 where age=21 for update;
Мы видим, что в mysql на самом деле нет блокировки:
Транзакция 2
insert into test01(id,name,age) values(8,'zzh',22);
В это время, поскольку [21,23) имеет блокировку пробела, будет заблокирована транзакция 2. В это время посмотрите на запись блокировки в mysql
Видно, что хотя транзакция 1 использовала... для обновления в начале, была добавлена неявная блокировка, поскольку конфликта не было, при запуске транзакции 2 возник конфликт, поэтому блокировка транзакции 1 была изменена на реальную замок.2. Анализ блокировки и практика
В частности, при разных уровнях изоляции транзакций анализ блокировок в разных сценариях, вАнализ замка HedechengЭта статья уже объясняла это очень подробно, поэтому я не буду говорить больше здесь. В основном говорят о каком-то анализе блокировки, обобщенном в других ситуациях.
2.1 Вставьте замки намерения
Первый взглядОфициальный сайт объясняет блокировку
Сосредоточимся на красной области: при возникновении конфликта к местоположению индекса будет добавлена блокировка S, а общая блокировка может легко привести к взаимоблокировке.На официальном сайте есть пример, специально объясняющий эту общую блокировку. Возникает взаимоблокировка, то есть три коллеги по транзакции выполняют оператор вставки, и одна из транзакций откатывается, что приводит к взаимоблокировке: Мы можем просто снова смоделировать эту ситуацию: Транзакция 1 insert into test01(id,name,age)values(12,"zzh",33);
Транзакция 2
insert into test01(id,name,age)values(12,"zzh",33);
Транзакция 3
insert into test01(id,name,age)values(12,"zzh",33);
Действуйте, как показано ниже:
Посмотрим на записи блокировок в Mysql Среди них это доказывает, что когда блокировка намерения конфликтует, запрашивается блокировка S, а затем мы откатываем транзакцию 1.Транзакция 1
rollback
В это время мы видим, что транзакция 2 прошла успешно, а транзакция 3 зашла в тупик.
Мы можем видеть из журнала взаимоблокировки:
- Транзакция 2: Ожидание блокировки намерения вставки с режимом блокировки X
- Транзакция 3: ожидание блокировки намерения вставки с режимом блокировки X; владение блокировкой записи с режимом блокировки S
- Подразумеваемое условие: транзакция 2 также имеет блокировку записи с режимом блокировки S, что приводит к взаимоблокировке.Журнал взаимоблокировок не будет распечатывать блокировки, уже принадлежащие транзакции, которая, наконец, успешно получила блокировку.
Таким образом, возникает транзакция 2-> транзакция 3, транзакция 3-> транзакция 2.
На официальном сайте есть еще один похожий пример, поэтому я не буду здесь больше анализировать по тем же причинам.
Давайте рассмотрим другую ситуацию:
Транзакция 1 (идентификатор транзакции = 2944)select * from test01 where age=21 for update;
Транзакция 2 (идентификатор транзакции = 2945)
insert into test01(id,name,age)values(2,"zzh",22);
Транзакция 3 (идентификатор транзакции = 2946)
select * from test01 where age=21 lock in share mode;
Выполнить следующим образом
Заблокировать записи в mysql Мы видим, что- Транзакция 1: (X, RECORD LOCK) в первичном ключе, (X, RECORD LOCK) в age_idx
- Транзакция 2: в (S, RECORD LOCK) первичного ключа, как мы упоминали ранее, транзакция 2 имеет конфликт при получении блокировки намерения вставки, поэтому она заблокирована для получения (S, RECORD LOCK)
- Транзакция 3: (S, RECORD LOCK) в age_idx,
Затем мы фиксируем транзакцию 1Транзакция 1
commit;
- Транзакция 2: блокировка S была успешно добавлена, но произошел конфликт уникальных ключей, и об ошибке было сообщено напрямую.Существует очень важный момент, обнаруженный в наличии записи, сразу после получения успеха транзакции банк плюс S-блокировка, но, несмотря на то, что он был предоставлен, S-блокировки не снимаются.
- Транзакция 3: Блокировка S получена успешно, но она находится на age_idx, что отличается от транзакции 2.
Давайте повторно выполним транзакцию 1
Транзакция 1 (идентификатор транзакции = 29467)
select * from test01 where age=21 for update;
Результат выполнения блокируется:
Давайте посмотрим на записи блокировки в mysql:Видно, что транзакция 3 имеет блокировку S на age_idx, которая блокирует блокировку X для получения транзакцией 1. В это время мы отправляем транзакцию 3.Транзакция 3 commit; Мы обнаружили, что транзакция 1 все еще заблокирована, посмотрите записи блокировки в mysql. Теперь я понимаю,Хотя транзакция 2 не может быть выполнена, блокировка S, добавленная из-за конфликта блокировок намерения вставки, не снимается, поэтому транзакция 1 по-прежнему заблокирована.. Только когда мы фиксируем транзакцию 2, транзакция 1 действительно выполняется.2.2 select...for update
Блокировка оператора делится на два случая
- Запись существует: если в режиме RC добавить (X, RECORD LOCK), в режиме RR добавить (X, NEXT-KEY LOCK), блокировки несовместимы друг с другом
- Запись не существует: добавить (X, GAP) LOCK, а блокировка совместима,Но он не совместим с блокировками Insert Intention Locks, что может легко привести к тупиковой ситуации.
2.2.1 Ожидание взаимоблокировки между разными индексами
Транзакция 1select * from test01 where age=21 for update;
Транзакция 2
insert into test01(id,name,age)values(3,"zzh",22);
Транзакция 1
insert into test01(id,name,age)values(3,"zzh",100);
Выполните результаты в указанном выше порядке:
Мы обнаружили, что возникла взаимоблокировка, и транзакция 1 была успешно выполнена после того, как транзакция 2 была отменена mysql. Давайте посмотрим на конкретный журнал взаимоблокировок. Через журнал взаимоблокировок мы можем его проанализировать- Транзакция 1: с age_idx (X, NEXT-KEY LOCK) возникает конфликт с блокировкой намерения вставки, поэтому дождитесь (S, RECORD LOCK) в позиции id=3.
- Транзакция 2: ожидание блокировки намерения вставки age_idx (блокировка намерения вставки доступна не только для первичного ключа)
- Неявные условия: хотя транзакция 2 ожидает блокировку намерения вставки в age_idx, блокировка намерения вставки в позиции id=3 выполнена успешно, поэтому возникает конфликт в транзакции 1, добавляющей блокировку намерения вставки в этой позиции.
2.2.2 Тупик, вызванный отсутствием записей
Транзакция 1 (идентификатор транзакции = 29684)select * from test01 where age=21 for update;
Транзакция 2 (идентификатор транзакции = 29683)
select * from test01 where age=21 for update;
Транзакция 1
insert into test01(id,name,age)values(3,"zzh",22);
Результат выполнения следующий
можно увидеть- Транзакция 1 и транзакция 2 одновременно удерживают блокировку пробела для записи age = 22. Поскольку запись не существует, блокировка пробела в это время совместима.
- Однако в записи нет совместимой блокировки промежутка, а блокировка намерения вставки несовместима, поэтому блокировка намерения вставки, запрошенная транзакцией 1 для индекса age=22, будет ожидать.
Транзакция 2
insert into test01(id,name,age)values(3,"zzh",22);
Из приведенного выше анализа также можно сделать вывод, что есть два случая ожидания транзакции 2:
(1) Как и транзакция 1, дождитесь блокировки намерения вставки для возраста = 22. В это время обнаружено, что транзакция 1 уже ожидает блокировку намерения вставки в этой позиции, затем дождитесь блокировки S в этой позиции.
(2) Хотя транзакция 1 ожидает блокировки намерения вставки с возрастом = 22, блокировка намерения вставки с id = 3 успешно добавлена, поэтому, если транзакция 2 ожидает блокировки намерения вставки с id = 3, также будет конфликта, то просто дождитесь блокировки S в этом месте
Следовательно, обе эти ситуации приведут к взаимоблокировке в транзакции.Рассмотрим лог взаимоблокировки подробно:
Мы видели:- Транзакция 1 ожидает блокировку намерения вставки в возрасте 22 лет.
- Транзакция 2 ожидает блокировки S с идентификатором = 3, что является вторым проанализированным нами случаем, а транзакция 2 имеет блокировку пробела с возрастом = 22.
Как мы проанализировали выше, ожидание транзакции 2 должно быть в двух случаях, и эти два случая могут быть оператором транзакции 2.
insert into test01(id,name,age)values(3,"zzh",22);
Мы узнали, что когда запись не существует, если для этой записи выполняется оператор select...for update, оператор добавит блокировку пробела в пустую позицию, что более опасно. первичный ключ, и в это время, если вы запросите несуществующую запись, она добавит блокировки пробелов ко всем пробелам, которые будут вставлены в будущем, что приведет к тому, что данные не будут вставлены в таблицу в будущем, что является чрезвычайно опасен.
3. Резюме
В этой статье мы представили блокировки в mysql и некоторые взаимоблокировки, с которыми можно столкнуться на практике, и проанализировали их с помощью нескольких демонстраций.Для анализа блокировок в статье hedecheng, упомянутой в статье, есть глубокое объяснение , поэтому эта статья не обобщает его. Суть в том, чтобы проанализировать весь процесс на нескольких практических примерах. Основное внимание уделяется блокировкам намерения вставки и некоторому анализу блокировок в select...for update. В следующей статье будет представлен механизм MVCC для mysql.