Ответ 1
Начиная с MySQL 5.7, схема производительности предоставляет все блокировки метаданных, включая блокировки, связанные с функцией GET_LOCK()
.
См. http://dev.mysql.com/doc/refman/5.7/en/metadata-locks-table.html
Есть ли способ выбрать/показать все текущие блокировки, которые были сняты с помощью GET_LOCK
function?
Обратите внимание, что блокировки GET_LOCK
отличаются от блокировок таблиц, таких как те, которые получены с помощью LOCK TABLES
- читателей, которые хотят знать, как видеть эти блокировки, должны читать Обнаружение заблокированных таблиц (заблокировано по LOCK TABLE)
Начиная с MySQL 5.7, схема производительности предоставляет все блокировки метаданных, включая блокировки, связанные с функцией GET_LOCK()
.
См. http://dev.mysql.com/doc/refman/5.7/en/metadata-locks-table.html
SHOW FULL PROCESSLIST;
Вы увидите блокировки там
Начиная с MySQL 5.7, это возможно, но сначала требуется включить инструмент mdl
в таблице performance_schema.setup_instruments
. Вы можете сделать это временно (до следующего перезапуска сервера), выполнив:
UPDATE performance_schema.setup_instruments
SET enabled = 'YES'
WHERE name = 'wait/lock/metadata/sql/mdl';
Или навсегда, добавив следующее заклинание в раздел [mysqld]
вашего файла my.cnf
(или любые файлы конфигурации, которые MySQL читает из вашей установки):
[mysqld]
performance_schema_instrument = 'wait/lock/metadata/sql/mdl=ON'
(Естественно, MySQL нужно будет перезапустить, чтобы изменения конфигурации вступили в силу, если вы примете последний подход.)
Блокировки, которые вы вынимаете после включения инструмента mdl
, можно увидеть, запустив SELECT
в таблице performance_schema.metadata_locks
, Как отмечено в документах, блокировки GET_LOCK
имеют OBJECT_TYPE
'USER LEVEL LOCK'
, поэтому мы можем отфильтровать наш запрос до них с помощью предложения WHERE
:
mysql> SELECT GET_LOCK('foobarbaz', -1);
+---------------------------+
| GET_LOCK('foobarbaz', -1) |
+---------------------------+
| 1 |
+---------------------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE='USER LEVEL LOCK'
-> \G
*************************** 1. row ***************************
OBJECT_TYPE: USER LEVEL LOCK
OBJECT_SCHEMA: NULL
OBJECT_NAME: foobarbaz
OBJECT_INSTANCE_BEGIN: 139872119610944
LOCK_TYPE: EXCLUSIVE
LOCK_DURATION: EXPLICIT
LOCK_STATUS: GRANTED
SOURCE: item_func.cc:5482
OWNER_THREAD_ID: 35
OWNER_EVENT_ID: 3
1 row in set (0.00 sec)
mysql>
Значения столбцов в этом результате в значительной степени документируются в https://dev.mysql.com/doc/refman/en/metadata-locks-table.html, но стоит упомянуть одну точку смятения: t214 > не содержит идентификатор соединения (например, будет показан в PROCESSLIST
или возвращен CONNECTION_ID()
) потока, который содержит блокировку. Смутно, термин "идентификатор потока" иногда используется как синоним "идентификатора соединения" в документации MySQL, но это не одно из тех случаев. Если вы хотите определить идентификатор соединения, в котором хранится блокировка (например, чтобы убить это соединение с помощью KILL
) вам нужно найти PROCESSLIST_ID
, который соответствует THREAD_ID
в таблице performance_schema.threads
. Например, чтобы убить соединение, которое удерживало мой замок выше...
mysql> SELECT OWNER_THREAD_ID FROM performance_schema.metadata_locks
-> WHERE OBJECT_TYPE='USER LEVEL LOCK'
-> AND OBJECT_NAME='foobarbaz';
+-----------------+
| OWNER_THREAD_ID |
+-----------------+
| 35 |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT PROCESSLIST_ID FROM performance_schema.threads
-> WHERE THREAD_ID=35;
+----------------+
| PROCESSLIST_ID |
+----------------+
| 10 |
+----------------+
1 row in set (0.00 sec)
mysql> KILL 10;
Query OK, 0 rows affected (0.00 sec)
Если вы просто хотите определить, находится ли конкретная именованная блокировка в настоящее время, вы можете использовать IS_USED_LOCK
:
SELECT IS_USED_LOCK('foobar');
Если какое-либо соединение содержит блокировку, этот идентификатор соединения будет возвращен; в противном случае результат NULL
.
Другим простым способом является использование:
mysqladmin debug
Это сбрасывает много информации (включая блокировки) в журнал ошибок.
Я нашел следующий способ, который можно использовать, если вы ЗНАЕТ имя блокировки
select IS_USED_LOCK('lockname');
однако я не нашел никакой информации о том, как перечислить все имена.
Ссылка, взятая из этой публикации:
Вы также можете использовать этот script для поиска блокировки в MySQL.
SELECT
pl.id
,pl.user
,pl.state
,it.trx_id
,it.trx_mysql_thread_id
,it.trx_query AS query
,it.trx_id AS blocking_trx_id
,it.trx_mysql_thread_id AS blocking_thread
,it.trx_query AS blocking_query
FROM information_schema.processlist AS pl
INNER JOIN information_schema.innodb_trx AS it
ON pl.id = it.trx_mysql_thread_id
INNER JOIN information_schema.innodb_lock_waits AS ilw
ON it.trx_id = ilw.requesting_trx_id
AND it.trx_id = ilw.blocking_trx_id