lock - mysql select for update ejemplo
Mostrar todos los bloqueos actuales de get_lock (7)
A partir de MySQL 5.7, el esquema de rendimiento expone todos los bloqueos de metadatos, incluidos los bloqueos relacionados con la función GET_LOCK()
.
Consulte http://dev.mysql.com/doc/refman/5.7/en/metadata-locks-table.html
¿Hay alguna forma de seleccionar / mostrar todos los bloqueos actuales que se han eliminado utilizando la función GET_LOCK
?
Tenga en cuenta que los bloqueos GET_LOCK
son diferentes de los bloqueos de tabla, como los que se GET_LOCK
con las LOCK TABLES
: los lectores que quieran saber cómo ver esos bloqueos deben leer Detectar tablas bloqueadas (bloqueado por TABLA DE BLOQUEO)
Desde MySQL 5.7 en adelante, esto es posible, pero requiere primero habilitar el instrumento mdl
en la tabla performance_schema.setup_instruments
. Puede hacerlo temporalmente (hasta que el servidor se reinicie) ejecutando:
UPDATE performance_schema.setup_instruments
SET enabled = ''YES''
WHERE name = ''wait/lock/metadata/sql/mdl'';
O permanentemente, agregando el siguiente encantamiento a la sección [mysqld]
de su archivo my.cnf
(o cualquier archivo de configuración que MySQL lea en su instalación):
[mysqld]
performance_schema_instrument = ''wait/lock/metadata/sql/mdl=ON''
(Naturalmente, será necesario reiniciar MySQL para que el cambio de configuración surta efecto si adopta este último enfoque).
Los bloqueos que saca después de que se haya habilitado el instrumento mdl
se pueden ver ejecutando un SELECT
en la tabla performance_schema.metadata_locks
. Como se señala en los documentos, los bloqueos GET_LOCK
tienen un OBJECT_TYPE
de ''USER LEVEL LOCK''
, por lo que podemos filtrar nuestra consulta hacia ellos con una cláusula 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>
La mayoría de los significados de las columnas en este resultado están adecuadamente documentados en performance_schema.metadata_locks , pero vale la pena señalar un punto de confusión: la columna OWNER_THREAD_ID
sí no contiene la ID de conexión (como se mostraría en la PROCESSLIST
o devuelta por CONNECTION_ID()
) del hilo que contiene el bloqueo. Confusamente, el término "ID de hilo" se usa a veces como sinónimo de "ID de conexión" en la documentación de MySQL, pero esta no es una de esas veces. Si desea determinar el ID de conexión de la conexión que mantiene un bloqueo (por ejemplo, para anular esa conexión con KILL
), deberá buscar el PROCESSLIST_ID
que corresponde al THREAD_ID
en la tabla performance_schema.threads
. Por ejemplo, para matar la conexión que mantenía mi cerradura arriba ...
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)
Encontré la siguiente forma que se puede usar si SABES el nombre de la cerradura
select IS_USED_LOCK(''lockname'');
Sin embargo, no he encontrado ninguna información sobre cómo enumerar todos los nombres.
Otra forma fácil es usar:
mysqladmin debug
Esto descarga mucha información (incluidos los bloqueos) en el registro de errores.
Si solo desea determinar si un bloqueo con nombre en particular se mantiene actualmente, puede usar IS_USED_LOCK
:
SELECT IS_USED_LOCK(''foobar'');
Si alguna conexión mantiene el bloqueo, se devolverá la ID de esa conexión; de lo contrario, el resultado es NULL
.
Referencia tomada de este post:
También puede usar este script para encontrar el bloqueo en 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
SHOW FULL PROCESSLIST;
Verás las cerraduras allí.