(1) 表锁
表锁的语法是 lock tables … read/write 可以用 unlock tables 主动释放锁 ,可以是客户端断开时候自动释放。需要注意的是,lock tables 语法除了会限制别的线程读写外,也下定了本线程接下来的操作
lock tables t1 read, t2 write 这个语句则其他线程写t1表,读t2表都会被阻塞。同时A在执行unlock tables 之前,也只能执行读t1,读写t2
(2)元数据锁
MDL锁是为了在访问表数据的时候,表结构不会被变更
当对一个表做增删改查操作的时候,加MDL读锁;当对表做结构变更操作的时候,加MDL写锁
读锁之间不互斥,因此可以有多个线程同时对一个表增删改查
读写锁之间,写锁之间是互斥的,用来保证表结构操作更安全
session1:
(root@33306) [test]> begin;
Query OK, 0 rows affected (0.00 sec)
(root@33306) [test]> select *from t2 limit 1;
+------+--------+
| c1 | c2 |
+------+--------+
| NULL | mothra |
+------+--------+
1 row in set (0.00 sec)
session2:
(root@33306) [test]> select *from t2 limit 1;
+------+--------+
| c1 | c2 |
+------+--------+
| NULL | mothra |
+------+--------+
1 row in set (0.00 sec)
(root@33306) [test]> alter table t2 add id int;
hang 住
原因是: session1 对表t2加了MDL读锁,session2 对表T2要加MDL写锁,两个锁互斥,所以session2 hang住
查看哪些表被锁了
(root@33306) [test]> show open tables where in_use>0;
+----------+-------+--------+-------------+
| Database | Table | In_use | Name_locked |
+----------+-------+--------+-------------+
| test | t2 | 1 | 0 |
+----------+-------+--------+-------------+
1 row in set (0.00 sec)
(root@33306) [(none)]> SELECT
-> a.trx_id,
-> b.ID,
-> b.STATE,
-> b.COMMAND,
-> b.`USER`,
-> b.`HOST`,
-> b.DB,
-> a.trx_weight,
-> a.trx_query,
-> a.trx_tables_locked,
-> a.trx_state,
-> a.trx_started,
-> a.trx_requested_lock_id,
-> a.trx_wait_started,
-> a.trx_mysql_thread_id
-> FROM information_schema.INNODB_TRX a ,information_schema.PROCESSLIST b where a.trx_mysql_thread_id=ID
->
-> ;
+-----------------+-------+-------+---------+------+-----------------+------+------------+-----------+-------------------+-----------+---------------------+-----------------------+------------------+---------------------+
| trx_id | ID | STATE | COMMAND | USER | HOST | DB | trx_weight | trx_query | trx_tables_locked | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_mysql_thread_id |
+-----------------+-------+-------+---------+------+-----------------+------+------------+-----------+-------------------+-----------+---------------------+-----------------------+------------------+---------------------+
| 421614036035408 | 27123 | | Sleep | root | localhost:56969 | test | 0 | NULL | 0 | RUNNING | 2019-01-08 09:54:50 | NULL | NULL | 27123 |
+-----------------+-------+-------+---------+------+-----------------+------+------------+-----------+-------------------+-----------+---------------------+-----------------------+------------------+---------------------+
1 row in set (0.00 sec)
可以发现是27123 这个session1 发起的,通过show processlist 查看,可以发现27071 在Waiting for table metadata lock
(root@33306) [(none)]> show processlist;
+-------+-----------------+--------------------+------+---------+---------+---------------------------------+-----------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-------+-----------------+--------------------+------+---------+---------+---------------------------------+-----------------------------+
| 1 | event_scheduler | localhost | NULL | Daemon | 1107864 | Waiting on empty queue | NULL |
| 27071 | root | localhost:55892 | test | Query | 132 | Waiting for table metadata lock | alter table t2 add id3 int |
| 27087 | root | 192.168.9.44:62103 | NULL | Sleep | 17 | | NULL |
| 27123 | root | localhost:56969 | test | Sleep | 27 | | NULL |
| 27125 | monitor | anedbtest01:36359 | NULL | Sleep | 1 | | NULL |
| 27127 | monitor | anedbtest01:36417 | NULL | Sleep | 31 | | NULL |
| 27129 | root | localhost:57073 | NULL | Query | 0 | starting | show processlist |
+-------+-----------------+--------------------+------+---------+---------+---------------------------------+-----------------------------+
7 rows in set (0.00 sec)
从上面可以看到27123 线程加了的MDL锁,阻塞了27071线程的MDL锁,根据业务是否可以杀掉27123线程