Spec-Zone.ru › MySQL 5.7

13.3.5 Заявления LOCK TABLES и UNLOCK TABLES

LOCK {TABLE | TABLES}
    tbl_name [[AS] alias] lock_type
    [, tbl_name [[AS] alias] lock_type] ...

lock_type: {
    READ [LOCAL]
  | [LOW_PRIORITY] WRITE
}

UNLOCK {TABLE | TABLES}

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

Блокировки могут использоваться для эмуляции транзакций или для увеличения скорости при обновлении таблиц. Подробно это описано в Ограничения и условия блокировки таблиц.

LOCK TABLES явно получает блокировки таблиц для текущей клиентской сессии. Блокировки таблиц могут быть получены для базовых таблиц или представлений. У вас должна быть привилегия LOCK TABLES, а также привилегия SELECT для каждого объекта, который будет заблокирован.

Для блокировки представлений LOCK TABLES добавляет все базовые таблицы, используемые в представлении, в набор таблиц, которые будут заблокированы, и автоматически блокирует их. Начиная с MySQL 5.7.32, LOCK TABLES проверяет, обладает ли определяющий представление пользователь надлежащими привилегиями для таблиц, лежащих в основе представления.

Если вы явно блокируете таблицу с помощью LOCK TABLES, все таблицы, используемые в триггерах, также неявно блокируются, как описано в LOCK TABLES и триггеры.

UNLOCK TABLES явно снимает любые блокировки таблиц, удерживаемые текущей сессией. LOCK TABLES неявно снимает любые блокировки таблиц, удерживаемые текущей сессией, прежде чем получать новые блокировки.

Другое применение UNLOCK TABLES заключается в снятии глобальной блокировки чтения, полученной с помощью оператора FLUSH TABLES WITH READ LOCK, который позволяет заблокировать все таблицы во всех базах данных. См. Раздел 13.7.6.3, «Оператор FLUSH». (Это очень удобный способ создания резервных копий, если у вас есть файловая система, такая как Veritas, которая может создавать моментальные снимки во времени.)

LOCK TABLE является синонимом LOCK TABLES; UNLOCK TABLE является синонимом UNLOCK TABLES.

Блокировка таблицы защищает только от некорректного чтения или записи другими сессиями. Сессия, удерживающая блокировку WRITE, может выполнять операции на уровне таблицы, такие как DROP TABLE или TRUNCATE TABLE. Для сессий, удерживающих блокировку READ, операции DROP TABLE и TRUNCATE TABLE запрещены.

Следующее обсуждение относится только к таблицам, не являющимся TEMPORARY. LOCK TABLES разрешено (но игнорируется) для TEMPORARY таблицы. К таблице может свободно обращаться сессия, в рамках которой она была создана, независимо от других действующих блокировок. Блокировка не требуется, поскольку другая сессия не может видеть таблицу.

  • Получение блокировки таблицы

  • Снятие блокировки таблицы

  • Взаимодействие блокировки таблиц и транзакций

  • LOCK TABLES и триггеры

  • Ограничения и условия блокировки таблиц

Получение блокировки таблицы

Для получения блокировок таблиц в текущей сессии используйте оператор LOCK TABLES, который получает блокировки метаданных (см. Раздел 8.11.4, «Блокировка метаданных»).

Доступны следующие типы блокировок:

Блокировка READ [LOCAL]:

  • Сессия, которая удерживает блокировку, может читать таблицу (но не записывать в неё).

  • Несколько сессий могут одновременно получить блокировку READ для таблицы.

  • Другие сессии могут читать таблицу, не получая явно блокировку READ.

  • Модификатор LOCAL позволяет выполнять неконфликтующие операторы INSERT (одновременные вставки) другими сессиями во время удерживания блокировки. (См. Раздел 8.11.3, «Одновременные вставки»). Однако READ LOCAL не может использоваться, если вы собираетесь управлять базой данных с помощью процессов, внешних по отношению к серверу, в то время, когда удерживаете блокировку. Для InnoDB таблиц, READ LOCAL равно READ.

Блокировка [LOW_PRIORITY] WRITE:

  • Сессия, которая удерживает блокировку, может читать и записывать в таблицу.

  • Только сессия, которая удерживает блокировку, может получить доступ к таблице. Никакая другая сессия не может получить к ней доступ до тех пор, пока блокировка не будет снята.

  • Запросы на блокировку таблицы другими сессиями блокируются во время удерживания блокировки WRITE.

  • Модификатор LOW_PRIORITY не оказывает никакого влияния. В предыдущих версиях MySQL он влиял на поведение блокировки, но это больше не так. Сейчас он устарел и его использование вызывает предупреждение. Используйте WRITE без LOW_PRIORITY вместо него.

Блокировки WRITE обычно имеют более высокий приоритет, чем блокировки READ, чтобы обеспечить как можно более быстрое выполнение обновлений. Это означает, что если одна сессия получает блокировку READ, а затем другая сессия запрашивает блокировку WRITE, последующие запросы на блокировку READ ожидают, пока сессия, запросившая блокировку WRITE, получит и снимет блокировку. (Исключение из этого правила может произойти для малых значений системной переменной max_write_lock_count; см. Раздел 8.11.4, «Блокировка метаданных».)

Если оператор LOCK TABLES должен ждать из-за блокировок, удерживаемых другими сессиями на любых таблицах, он блокируется до тех пор, пока все блокировки не будут получены.

Сессия, требующая блокировок, должна получить все необходимые блокировки в одном операторе LOCK TABLES. Пока удерживаются полученные блокировки, сессия может обращаться только к заблокированным таблицам. Например, в следующей последовательности операторов возникает ошибка при попытке доступа к t2, так как она не была заблокирована в операторе LOCK TABLES:

mysql> LOCK TABLES t1 READ;
mysql> SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
|        3 |
+----------+
mysql> SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES

Таблицы в базе данных INFORMATION_SCHEMA являются исключением. К ним можно получить доступ без явного блокирования, даже когда сессия удерживает блокировки таблиц, полученные с помощью LOCK TABLES.

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

mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

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

Если ваши операторы ссылаются на таблицу с помощью псевдонима, вы должны заблокировать таблицу, используя этот же псевдоним. Не работает блокировка таблицы без указания псевдонима:

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

И наоборот, если вы блокируете таблицу с помощью псевдонима, вы должны ссылаться на неё в ваших операторах, используя этот же псевдоним:

mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;
Примечание

LOCK TABLES или UNLOCK TABLES, когда применяется к разбиеной таблице, всегда блокируют или разблокируют всю таблицу; эти операторы не поддерживают прореживание блокировки разбиений. См. Раздел 22.6.4, «Разбиение и блокировка».

Освобождение блокировки таблицы

При освобождении блокировок таблиц, удерживаемых сеансом, все блокировки освобождаются одновременно. Сеанс может явно освободить свои блокировки или блокировки могут быть освобождены неявно в определенных условиях.

  • Сеанс может явно освободить свои блокировки с помощью UNLOCK TABLES.

  • Если сеанс выполняет оператор LOCK TABLES для получения блокировки, при этом уже удерживая блокировки, его существующие блокировки освобождаются неявно перед предоставлением новых блокировок.

  • Если сеанс начинает транзакцию (например, с помощью START TRANSACTION), выполняется неявное UNLOCK TABLES, которое вызывает освобождение существующих блокировок. (Для получения дополнительной информации о взаимодействии блокировки таблиц и транзакций см. Взаимодействие блокировки таблиц и транзакций.)

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

Примечание

Если вы используете ALTER TABLE для заблокированной таблицы, она может быть разблокирована. Например, если вы попытаетесь выполнить вторую операцию ALTER TABLE, результатом может быть ошибка Table 'tbl_name' was not locked with LOCK TABLES. Для решения этой проблемы заблокируйте таблицу снова перед второй модификацией. См. также Раздел B.3.6.1, «Проблемы с ALTER TABLE».

Взаимодействие блокировки таблиц и транзакций

LOCK TABLES и UNLOCK TABLES взаимодействуют с использованием транзакций следующим образом:

  • LOCK TABLES не является безопасной для транзакций и неявно фиксирует любую активную транзакцию перед попыткой заблокировать таблицы.

  • UNLOCK TABLES неявно фиксирует любую активную транзакцию, но только если LOCK TABLES был использован для получения блокировок таблиц. Например, в следующем наборе операторов, UNLOCK TABLES освобождает глобальную блокировку чтения, но не фиксирует транзакцию, так как блокировки таблиц не действуют:

    FLUSH TABLES WITH READ LOCK;
    START TRANSACTION;
    SELECT ... ;
    UNLOCK TABLES;
    
  • Начало транзакции (например, с помощью START TRANSACTION) неявно фиксирует любую текущую транзакцию и освобождает существующие блокировки таблиц.

  • FLUSH TABLES WITH READ LOCK получает глобальную блокировку чтения, а не блокировки таблиц, поэтому он не подвержен такому же поведению, как LOCK TABLES и UNLOCK TABLES по отношению к блокировке таблиц и неявным фиксациям. Например, START TRANSACTION не освобождает глобальную блокировку чтения. См. Раздел 13.7.6.3, «FLUSH оператор».

  • Другие операторы, которые неявно вызывают фиксацию транзакций, не освобождают существующие блокировки таблиц. Список таких операторов см. в Разделе 13.3.3, «Операторы, вызывающие неявную фиксацию».

  • Правильный способ использования LOCK TABLES и UNLOCK TABLES с транзакционными таблицами, такими как InnoDB таблицы, — это начать транзакцию с помощью SET autocommit = 0 (а не START TRANSACTION), за которым следует LOCK TABLES, и не вызывать UNLOCK TABLES до явного фиксации транзакции. Например, если вам нужно записать в таблицу t1 и прочитать из таблицы t2, вы можете сделать это:

    SET autocommit=0;
    LOCK TABLES t1 WRITE, t2 READ, ...;
    ... do something with tables t1 and t2 here ...
    COMMIT;
    UNLOCK TABLES;
    

    При вызове LOCK TABLES, InnoDB внутренне получает свою собственную блокировку таблицы, а MySQL получает свою собственную блокировку таблицы. InnoDB освобождает свою внутреннюю блокировку таблицы при следующей фиксации, но для того, чтобы MySQL освободил свою блокировку таблицы, вы должны вызвать UNLOCK TABLES. Не должно быть autocommit = 1, потому что тогда InnoDB освобождает свою внутреннюю блокировку таблицы сразу после вызова LOCK TABLES, и очень легко могут возникнуть тупики. InnoDB вообще не получает внутренней блокировки таблицы, если autocommit = 1, чтобы помочь старым приложениям избежать ненужных тупиков.

  • ROLLBACK не освобождает блокировки таблиц.

LOCK TABLES и триггеры

Если вы явно блокируете таблицу с помощью LOCK TABLES, любые таблицы, используемые в триггерах, также неявно блокируются:

  • Блокировки берутся одновременно с теми, которые получены явно с помощью оператора LOCK TABLES.

  • Блокировка таблицы, используемой в триггере, зависит от того, используется ли таблица только для чтения. Если это так, достаточно блокировки чтения. В противном случае используется блокировка записи.

  • Если таблица заблокирована явно для чтения с помощью LOCK TABLES, но ей может потребоваться блокировка записи, потому что она может быть изменена внутри триггера, то используется блокировка записи, а не блокировка чтения. (То есть неявная блокировка записи, необходимая из-за появления таблицы в триггере, приводит к тому, что явное запрошенное блокирование чтения таблицы преобразуется в запрос блокировки записи.)

Предположим, что вы блокируете две таблицы, t1 и t2, используя этот оператор:

LOCK TABLES t1 WRITE, t2 READ;

Если у t1 или t2 есть триггеры, таблицы, используемые в триггерах, также блокируются. Предположим, что t1 имеет определенный триггер, как показано ниже:

CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW
BEGIN
  UPDATE t4 SET count = count+1
      WHERE id = NEW.id AND EXISTS (SELECT a FROM t3);
  INSERT INTO t2 VALUES(1, 2);
END;

Результат оператора LOCK TABLES состоит в том, что t1 и t2 заблокированы, так как они указаны в операторе, и t3 и t4 заблокированы, так как они используются в триггере:

  • t1 заблокирована для записи в соответствии с запросом блокировки WRITE.

  • t2 заблокирована для записи, даже если запрос — блокировка READ. Это происходит, потому что t2 вставляется в триггер, поэтому запрос READ преобразуется в запрос WRITE.

  • t3 заблокирована для чтения, потому что она только считывается внутри триггера.

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

END_OF_DOCUMENT_MARKER

Ограничения и условия блокировки таблиц

Для безопасного завершения сессии, ожидающей блокировки таблицы, можно использовать KILL. См. Раздел 13.7.6.4, «Команда KILL».

Команды LOCK TABLES и UNLOCK TABLES не могут быть использованы внутри хранимых программ.

Таблицы в базе данных performance_schema не могут быть заблокированы с помощью LOCK TABLES, за исключением таблиц setup_xxx.

Область действия блокировки, созданной LOCK TABLES, ограничена одним сервером MySQL. Она не совместима с NDB Cluster, который не имеет возможности принудительного применения блокировки на уровне SQL через несколько экземпляров mysqld. Принудительную блокировку можно реализовать в приложении API. Дополнительную информацию см. в разделе 21.2.7.10, «Ограничения, связанные с несколькими узлами NDB Cluster».

Следующие команды запрещены, пока активна команда LOCK TABLES: CREATE TABLE, CREATE TABLE ... LIKE, CREATE VIEW, DROP VIEW, а также DDL-команды для хранимых функций, процедур и событий.

Для некоторых операций необходимо получить доступ к системным таблицам в базе данных mysql. Например, команда HELP требует содержимого таблиц справки на стороне сервера, а CONVERT_TZ() может потребовать чтения таблиц часовых поясов. Сервер неявно блокирует системные таблицы для чтения по мере необходимости, поэтому явное их блокирование не требуется. Эти таблицы обрабатываются как описано выше:

mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.proc
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type

Если вы хотите явно установить блокировку WRITE на любую из этих таблиц с помощью команды LOCK TABLES, то эта таблица должна быть единственной заблокированной; ни одна другая таблица не может быть заблокирована с помощью этой же команды.

Обычно блокировать таблицы не требуется, так как все отдельные команды UPDATE являются атомарными; ни одна другая сессия не может вмешаться в выполнение любой другой текущей SQL-команды. Однако есть несколько случаев, когда блокировка таблиц может быть выгодна:

  • Если вы собираетесь выполнить множество операций с набором таблиц MyISAM, гораздо быстрее заблокировать используемые таблицы. Блокировка таблиц MyISAM ускоряет вставки, обновления или удаления в них, потому что MySQL не очищает кэш индексов для заблокированных таблиц до вызова UNLOCK TABLES. Обычно кэш индексов очищается после каждой SQL-команды.

    Недостатком блокировки таблиц является то, что ни одна сессия не может обновить заблокированную таблицу READ (включая ту, которая держит блокировку), и ни одна сессия не может получить доступ к заблокированной таблице WRITE, кроме той, которая держит блокировку.

  • Если вы используете таблицы для нетранзакционного движка хранения, вам необходимо использовать LOCK TABLES, если вы хотите гарантировать, что ни одна другая сессия не модифицирует таблицы между SELECT и UPDATE. Приведенный пример требует LOCK TABLES для безопасного выполнения:

    LOCK TABLES trans READ, customer WRITE;
    SELECT SUM(value) FROM trans WHERE customer_id=some_id;
    UPDATE customer
      SET total_value=sum_from_previous_statement
      WHERE customer_id=some_id;
    UNLOCK TABLES;
    

    Без LOCK TABLES существует возможность того, что другая сессия вставит новую строку в таблицу trans между выполнением SELECT и UPDATE.

Во многих случаях можно избежать использования LOCK TABLES с помощью относительных обновлений (UPDATE customer SET value=value+new_value) или функции LAST_INSERT_ID().

Также можно избежать блокировки таблиц в некоторых случаях с помощью функций консультирования блокировки на уровне пользователя GET_LOCK() и RELEASE_LOCK(). Эти блокировки сохраняются в хеш-таблице на сервере и реализуются с использованием pthread_mutex_lock() и pthread_mutex_unlock() для высокой скорости. См. раздел 12.14, «Функции блокировки».

Дополнительную информацию о политике блокировки см. в разделе 8.11.1, «Внутренние методы блокировки».

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/lock-tables.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API