MySQL 表锁定
简介:在本教程中,您将学习如何使用MySQL锁定来在会话之间进行协作访问表。
锁是与表关联的标志。MySQL允许客户端会话显式获取表锁,以防止其他会话在特定时间段内访问同一个表。客户端会话只能为自己获取或释放表锁。它无法获取或释放其他会话的表锁。 在详细介绍之前,我们创建了一个
tbl
的表练习表锁定语句。
CREATE TABLE tbl ( id INT NOT NULL AUTO_INCREMENT, col INT NOT NULL, PRIMARY KEY (id) ) Engine = InnoDB;
LOCK和UNLOCK TABLES语法
以下语句显式获取表锁:LOCK TABLES table_name [READ | WRITE]要锁定表,请在
LOCK TABLES
关键字后指定其名称。此外,您可以指定锁的类型,可以是 READ
或 WRITE
。
要释放表的锁,请使用以下语句:
UNLOCK TABLES;
读锁
READ
锁具有以下特点:
READ
可以通过多个会话同时获取表的锁。此外,其他会话可以从表中读取数据而无需获取锁。- 持有
READ
锁的会话只能读取表中的数据,但无法写入。此外,在READ
释放锁之前,其他会话无法将数据写入表。来自另一个会话的写入操作将进入等待状态,直到READ
锁定被释放。 - 如果会话正常或异常终止,MySQL将隐式释放所有锁。此功能也与
WRITE
锁相关。
READ
锁在以下场景中的工作原理。
在第一个会话中,首先,连接到mysqldemo
数据库并使用CONNECTION_ID()
函数获取当前连接ID,如下所示:
SELECT CONNECTION_ID();
+-----------------+ | CONNECTION_ID() | +-----------------+ | 4892 | +-----------------+ 1 row in set (0.00 sec)然后,在
tbl
表中插入一个新行
。
INSERT INTO tbl(col) VALUES(10);接下来,查询
tbl
表中的数据。
SELECT * FROM tbl;
+----+-----+ | id | col | +----+-----+ | 1 | 10 | +----+-----+ 1 row in set (0.00 sec)之后,要获取锁定,请使用
LOCK TABLE
语句。
LOCK TABLE tbl READ;最后,在同一个会话中,如果您尝试在
tbl
表中插入新行,则会收到错误消息。
INSERT INTO tbl(col) VALUES(11);
ERROR 1099 (HY000): Table 'tbl' was locked with a READ lock and can't be updated因此,一旦
READ
获取了锁,就无法在同一会话中将数据写入表中。
让我们READ
从另一个会话中检查锁定。
首先,连接到mysqldemo
并检查连接ID:
SELECT CONNECTION_ID();
+-----------------+ | CONNECTION_ID() | +-----------------+ | 4896 | +-----------------+ 1 row in set (0.00 sec)然后,从
tbl
表中检索数据:
SELECT * FROM tbl;
+----+-----+ | id | col | +----+-----+ | 1 | 10 | +----+-----+ 1 row in set (0.00 sec)接下来,在
tbl
表中插入一个新行:
INSERT INTO tbl(col) VALUES(20);
mysql> INSERT INTO tbl(col) VALUES(20); ...来自第二个会话的插入操作处于等待状态,因为第一个会话
READ
已经在tbl
表上获取了锁,但尚未释放。
您可以从SHOW PROCESSLIST
查看详细信息。
SHOW PROCESSLIST;
mysql> SHOW PROCESSLIST;
+------+------+-----------------+-----------+---------+------+------------------------------+---------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------+-----------------+-----------+---------+------+------------------------------+---------------------------------+
| 4884 | root | localhost:64108 | mysqldemo | Sleep | 1479 | | NULL |
| 4892 | root | localhost | mysqldemo | Query | 0 | init | SHOW PROCESSLIST |
| 4896 | root | localhost | mysqldemo | Query | 97 | Waiting for table level lock | INSERT INTO tbl(col) VALUES(20) |
+------+------+-----------------+-----------+---------+------+------------------------------+---------------------------------+
3 rows in set (0.00 sec)
之后,返回第一个会话并使用UNLOCK TABLES
语句释放锁定。READ
从第一个会话释放锁定后,INSERT
执行第二个会话中的操作。
unlock tables;最后,检查
tbl
表的数据,看看INSERT
第二个会话的操作是否真的执行了。
SELECT * FROM tbl;
mysql> SELECT * FROM tbl; +----+-----+ | id | col | +----+-----+ | 1 | 10 | | 2 | 20 | +----+-----+ 2 rows in set (0.00 sec)
写锁
WRITE
锁具有以下特点:
- 保存表锁的唯一会话可以从表中读取和写入数据。
- 在
WRITE
锁定释放之前,其他会话无法从表中读取数据并将数据写入表中。
WRITE
锁是如何工作的。
首先,WRITE
从第一个会话中获取锁定。
LOCK TABLE tbl WRITE;然后,在
tbl
表中插入一个新行。
INSERT INTO tbl(col) VALUES(11);有用。 接下来,从
tbl
表中读取数据。
SELECT * FROM tbl;
+----+-----+ | id | col | +----+-----+ | 1 | 10 | | 2 | 20 | | 3 | 11 | +----+-----+ 3 rows in set (0.00 sec)它也有效。 之后,从第二个会话开始,尝试写入和读取数据:
INSERT INTO tbl(col) VALUES(21); SELECT * FROM tbl;MySQL将这些操作置于等待状态。您可以使用
SHOW PROCESSLIST
语句进行检查。
SHOW PROCESSLIST
+------+------+-----------------+-----------+---------+------+---------------------------------+---------------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------+-----------------+-----------+---------+------+---------------------------------+---------------------------------+
| 4884 | root | localhost:64108 | mysqldemo | Sleep | 2105 | | NULL |
| 4892 | root | localhost | mysqldemo | Query | 0 | init | SHOW PROCESSLIST |
| 4896 | root | localhost | mysqldemo | Query | 27 | Waiting for table metadata lock | INSERT INTO tbl(col) VALUES(21) |
+------+------+-----------------+-----------+---------+------+---------------------------------+---------------------------------+
最后,从第一个会话中释放锁定。
UNLOCK TABLES;您将看到第二个会话中的所有待处理操作都已执行,下图说明了结果:
+----+-----+ | id | col | +----+-----+ | 1 | 10 | | 2 | 20 | | 3 | 11 | | 4 | 21 | +----+-----+ 4 rows in set (0.00 sec)
读锁与写锁
- 读锁是“共享”锁,它可以防止正在获取写锁,但不能锁定其他读锁。
- 写锁是“独占”锁,可以防止任何其他类型的锁。