Глава 5. Уровни блокировок доступа

В самой первой главе где были введены блокировки, не было упоминания о том как работают блокировки. Было бы возможным реализовывать блокировку в базе данных просто просто разрешая по одному запросу за раз, причём вне зависимости от того какой вид действий будет осуществляться. Однако это было бы крайне недейственным.

продолжая аналогию со светофором, иной подход состоит в том, чтобы предоставлять доступ на основании того какая работа выполняется. Светофор предоставляет доступ к своему перекрёстку не только для одной машины, но и для всех, которые движутся в одном направлении. Точно также и в базе данных вы делаете отличие между совместными (считывание) и исключительными (на запись) доступом. Такие уровни доступа делают именно то, что и предполагает их название. Разделяемые блокировки позволяют прочим соединениям также получать некую совместную блокировку. Это уровень доступа блокировки с наибольшим разрешением. Разделяемая блокировка также именуется блокировкой считывания, а исключительная блокировка также имеет название блокировки записи.

[Замечание]Замечание

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

MySQL также обладает понятием с названием намерений блокировок, которые определяют собственно намерение некой транзакции. Намерение блокировки может быть совместным или исключительным.

Остаток данной главы вдаётся в дополнительные сведения относительно совместных и исключительных блокировок, а также намерений блокировок.

Совместные блокировки

Когда некому потоку необходимо защитить какой- то ресурс, но он не намерен изменять такой ресурс, он может воспользоваться совместной блокировкой чтобы препятствовать прочим потокам изменять этот ресурс и при этом всё ещё допуская для них доступ к тому же самому ресурсу. Это наиболее часто применяемый уровень доступа.

Всякий раз когда некий оператор выполняет выборку из таблицы, MySQL будет принимать некую совместную блокировку в такой вовлечённой в данный запрос таблице. Для блокируемых данных это работает иначе, поскольку InnoDB обычно не овладевает совместной блокировкой при считывании некой строки. Это происходит лишь тогда, когда некая совместная блокировка запрашивается в явном виде, на уровне SERIALIZABLE изоляции транзакции или же она требуется самим рабочим потоком, например, когда в него вовлечены внешние ключи.

Вы можете в явном виде запросить некую совместную блокировку на определённой строке при доступе к ней добавляя параметр FOR SHARE или его синоним LOCK IN SHARE MODE, как это отображено в Листинг 5-1.

 

Листинг 5-1. Пример получения совместной блокировки


-- Connection   Processlist ID   Thread ID   Event ID
-- --------------------------------------------------
--          1               36          80          6

-- Connection 1
Connection 1> START TRANSACTION;
Query OK, 0 rows affected (0.0003 sec)
Connection 1> SELECT * FROM world.city WHERE ID = 130 FOR SHARE;
+-----+--------+-------------+-----------------+------------+
| ID  | Name   | CountryCode | District        | Population |
+-----+--------+-------------+-----------------+------------+
| 130 | Sydney | AUS         | New South Wales |    3276207 |
+-----+--------+-------------+-----------------+------------+
1 row in set (0.0047 sec)

Connection 1> SELECT object_type, object_schema, object_name,
                     lock_type, lock_duration, lock_status
                FROM performance_schema.metadata_locks
               WHERE OWNER_THREAD_ID = PS_CURRENT_THREAD_ID()
                     AND OBJECT_SCHEMA <> 'performance_schema'\G
*************************** 1. row ***************************
  object_type: TABLE
object_schema: world
  object_name: city
    lock_type: SHARED_READ
lock_duration: TRANSACTION
  lock_status: GRANTED
1 row in set (0.0005 sec)

Connection 1> SELECT engine, object_schema, object_name,
                     lock_type, lock_mode, lock_status
                FROM performance_schema.data_locks
               WHERE THREAD_ID = PS_CURRENT_THREAD_ID()\G
*************************** 1. row ***************************
       engine: INNODB
object_schema: world
  object_name: city
    lock_type: TABLE
    lock_mode: IS
  lock_status: GRANTED
*************************** 2. row ***************************
       engine: INNODB
object_schema: world
  object_name: city
    lock_type: RECORD
    lock_mode: S,REC_NOT_GAP
  lock_status: GRANTED
2 rows in set (0.0005 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.0004 sec)
 	   

При выполнении запроса к таблице metadata_locks, из таблиц схемы Производительности исключаются блокировки, ибо они служат для самого расследовательского запроса вместо того чтобы предназначаться предыдущему запросу. В данном случае совместная блокировка выполняется для таблицы world.city, а также для той записи, у которой значение первичного ключа (столбец ID) равно 130. То, что они выступают совместными блокировками можно обнаружить в столбце lock_type из таблицы metadata_locks, который обладает значением SHARED_READ, а также из S в столбце lock_mode data_locks во второй строке. Значение IS для самой первой строки из data_locks означает что она выступает совместной блокировкой намерения, которая в скорости будет обсуждена.

В то время как совместные блокировки позволяю прочим запросам также применять для обработки совместные блокировки, они выполняют блокирование попыток получения исключительной блокировки.

Исключительные блокировки

Исключительные блокировки выступают противоположностью совместных блокировок. Они гарантируют что лишь тот поток, которому предоставлена такая исключительная блокировка способен выполнять доступ к данному ресурсу на протяжении этой блокировки. Поскольку исключительные блокировки применяются для гарантии того, что лишь единственный поток изменяет за раз некий ресурс, они также именуются блокировками записи.

Исключительные блокировки как правило получаются из таких операторов DDL (data definition language, языка определения данных), как ALTER TABLE, а также при изменении данных при помощи операторов DML (data modification language, языка изменения данных), например, UPDATE и DELETE. Некий образец получения исключительной блокировки и собственно данные в заблокированных таблицах можно обнаружить в Листинге 5-2.

 

Листинг 5-2. Пример получения исключительной блокировки


-- Connection   Processlist ID   Thread ID   Event ID
-- --------------------------------------------------
--          1               38          84          6
-- Connection 1
Connection 1> START TRANSACTION;
Query OK, 0 rows affected (0.0003 sec)

Connection 1> UPDATE world.city
                 SET Population = Population + 1
               WHERE ID = 130;
Query OK, 1 row affected (0.0028 sec)

Rows matched: 1  Changed: 1  Warnings: 0

Connection 1> SELECT object_type, object_schema, object_name,
                     lock_type, lock_duration, lock_status
                FROM performance_schema.metadata_locks
               WHERE OWNER_THREAD_ID = PS_CURRENT_THREAD_ID()
                     AND OBJECT_SCHEMA <> 'performance_schema'\G
*************************** 1. row ***************************
  object_type: TABLE
object_schema: world
  object_name: city
    lock_type: SHARED_WRITE
lock_duration: TRANSACTION
  lock_status: GRANTED
*************************** 2. row ***************************
  object_type: TABLE
object_schema: world
  object_name: country
    lock_type: SHARED_READ
lock_duration: TRANSACTION
  lock_status: GRANTED
2 rows in set (0.0008 sec)

Connection 1> SELECT engine, object_schema, object_name,
                     lock_type, lock_mode, lock_status
                FROM performance_schema.data_locks
               WHERE THREAD_ID = PS_CURRENT_THREAD_ID()\G
*************************** 1. row ***************************
       engine: INNODB
object_schema: world
  object_name: city
    lock_type: TABLE
    lock_mode: IX
  lock_status: GRANTED
*************************** 2. row ***************************
       engine: INNODB
object_schema: world
  object_name: city
    lock_type: RECORD
    lock_mode: X,REC_NOT_GAP
  lock_status: GRANTED
2 rows in set (0.0005 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.3218 sec)
 	   

Большинство примеров отражают собственно образцы получения совместных блокировок, но также имеется и ряд сюрпризов. Для начала, с таблицы data_locks, она показывает намерение исключительной блокировки вставки (IX) в этой таблице и исключительную блокировку записи (X). Всё это как ожидалось.

Всё становится несколько сложнее с таблицей metadata_locks, в которой теперь имеются две блокировки таблицы, блокировка SHARED_WRITE для таблицы city и блокировка SHARED_READ для таблицы country. Как некая блокировка может быть одновременно и совместной, и блокировкой записи, почему блокировка для таблицы city разделялась пока она изменялась и почему имеется блокировка в таблице country?

Блокировка SHARED_WRITE сообщает что её данные заблокированы под обновления, однако эти метаданные блокировки сами по себе являются совместной блокировкой. Основной причиной этого является то, что эти метаданные для соответствующей таблицы не изменяются, а потому безопасно позволять прочим конкурентам совместно выполнять доступ к метаданным такой таблицы. Помните что сама таблица metadata_locks не заботится относительно тех блокировок, которые удерживаются для индивидуальных записей, а потому с точки зрения метаданных, такой доступ к общей таблице city является совместным.

Конкретная блокировка метаданных в таблице country поступает от внешнего ключа из таблицы city в таблицу country. Такая разделяемая блокировка препятствует изменениям в метаданных country, например, отбросу тех столбцов, которые вовлечены во внешний ключ на протяжении выполнения данной транзакции. Глава 10 углубится в подробности относительно воздействия внешних ключей на блокирования.

Намерение блокировок

В тех двух примерах, которые мы привели в данной главе на текущий момент, имелись намерения блокировок. Что это такое? Это блокировка, которая сигнализирует определённое намерение транзакции InnoDB и она может быть либо совместной, либо исключительной. Она может показаться на первый взгляд не нужным усложнением, однако такое блокирование намерения делает возможным для InnoDB разрешать поступающие запросы блокировок по порядку без блокировки совместимых операций. Имеющиеся подробности выходят за рамки данного обсуждения. Важный момент состоит в том, что само намерение блокировки существует, а потому когда вы его обнаруживаете, вы знаете откуда оно поступает.

Намерения блокировок с более функциональной точки зрения рассматриваются в Главе 6, а относящиеся к ним понятия, намерения блокировок вставки обсуждаются совместно с блокировками InnoDB в Главе 7.

Совместимость блокировок

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

Две блокировки намерений всегда совместимы друг с другом. Это означает, что даже когда некая транзакция имеет намерение исключительной блокировки, оно не предотвратит другую транзакцию от получения какого- то намерения блокировки. Они однако остановят все прочие транзакции в обновлении своих намерений блокировок в полное блокирование. Таблица 5-1 отображает значения совместимости между имеющимися типами блокировок. Совместные блокировки обозначаются как S, а исключительные блокировки как X. Намерения блокирования предваряется I, а потому IS это намерение совместной блокировки, в то время как IX намерение исключительной блокировки.

Таблица 5-1. Совместимость блокировок innoDB
  Исключительная (X) Намерение исключительной (IX) Совместная (X) Намерение совместной (X)

Исключительная (X)

X

X

X

X

Намерение исключительной (IX)

X

V

X

V

Совместная (S)

X

X

V

V

Намерение совместной (IS)

X

V

V

V

В данной таблице галочка означает что две соответствующие блокировки совместимы, в то время как крест указывает что такие две блокировки конфликтуют друг с другом. Единственный конфликт намерений блокировок состоит между исключительными и совместными блокировками. Некая исключительная блокировка конфликтует со всеми прочими блокировками, включая оба типа намерений блокировок. Совместная блокировка конфликтует лишь с исключительной блокировкой и намерением исключительной блокировки.

Всё это звучит достаточно просто; тем не менее, это применимо лишь к двум блокировкам того же самого вида. Когда вы начинаете на уровне InnoDB включать различные блокировки, это становится более сложным и обсуждается в Главе 8, когда обсуждается содержимое блокировок.

Всё это автоматически обрабатывается MySQL и InnoDB; тем не менее, вам необходимо разбираться в этих правилах при расследовании проблем с блокировками.

Выводы

Эта глава рассматривала уровни доступа блокировок MySQL. Некая блокировка может быть либо совместной блокировкой, исключительной блокировкой, намерением совместной блокировки или намерением исключительной блокировки.

Совместные блокировки служат для доступа на считывание некого ресурса и позволяют множеству потоков одновременно выполнять доступ к одному и тому же ресурсу. Исключительная блокировка с другой стороны делает возможным доступ к ресурсу за раз лишь для единственного потока, что превращает обновление такого ресурса в безопасное.

Намерения блокировок являются понятием InnoDB, которое позволяет InnoDB разрешать запросы на блокирование с меньшим блокированием запросов в конечном результате. Все намерения блокировок совместимы друг с другом, даже намерения исключительных блокировок, однако намерение исключительной блокировки заблокирует совместные блокировки.

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