MysqL 服务器级别的锁等待
使用锁来控制资源共享的应用系统,如何处理锁的竞争问题是个头疼事。MysqL 有两个级别的锁等待,服务器级别和存储引擎级别,本节重点介绍服务器级别的锁等待。
1. 表锁
表锁可以是显式的,也可以是隐式的。
1.1 显式锁
MysqL> lock tables customer read;
Query OK, rows affected ( sec)
MysqL> lock tables customer write;
在第一个会话中执行 show processlist 查看线程状态,可以看到线程 13239868 的状态为 Waiting for table Metadata lock。在 MysqL 中,当一个线程持有该锁后,其他线程只能不断尝试获取。
MysqL> show processlist\G
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: starting
Info: show processlist
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: Waiting for table Metadata lock
Info: lock tables customer write
rows in set ( sec)
1.2 隐式锁
MysqL> select sleep() from customer;
MysqL> lock tables customer write;
在第三个会话中执行 show processlist 查看线程状态,可以看到线程 13244135 的状态为 Waiting for table Metadata lock。select 查询的隐式锁阻塞了 lock tables 中所请求的显式写锁。
MysqL> show processlist\G
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: User sleep
Info: select sleep() from customer
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: Waiting for table Metadata lock
Info: lock tables customer write
2. 全局锁
在 MysqL会 话中执行 flush tables 命令,获得全局读锁。
MysqL> flush tables with read lock;
Query OK, rows affected ( sec)
MysqL> lock tables customer write;
在第一个会话中执行 show processlist 查看线程状态,可以看到线程 13283816 的状态为 Waiting for global read lock。这是一个全局读锁,而不是表级别锁。
MysqL> show processlist\G
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: starting
Info: show processlist
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: Waiting for global read lock
Info: lock tables customer write
rows in set ( sec)
3. 命名锁
MysqL> lock tables customer read;
Query OK, rows affected ( sec)
MysqL> rename table customer to customer_1;
MysqL> show processlist\G
...
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: Waiting for table Metadata lock
Info: rename table customer to customer_1
4. 用户锁
在 MysqL 会话中执行 get_lock 命令,成功执行并持有一把锁。
MysqL> select get_lock('user_1',);
+------------------------+
| get_lock('user_1',) |
+------------------------+
| |
+------------------------+
row in set ( sec)
MysqL> select get_lock('user_1',);
+------------------------+
| get_lock('user_1',) |
+------------------------+
| |
+------------------------+
MysqL> show processlist\G
...
*************************** . row ***************************
Id:
User: root
Host: localhost
: tempdb
Command: Query
Time:
State: User lock
Info: select get_lock('user_1',)
5. 小结
本小节介绍了服务器级别的锁等待:表锁、全局锁、命名锁、用户锁。
表锁可以是显式的,也可以是隐式的。显式锁通过 lock tables 和 unlock tables 进行控制,隐式锁在查询过程中产生。全局锁可以通过 flush tables with read lock 或设置 read_only=1 来 实现,它与任何表锁都冲突。