MySQL锁定表

时间:2019-11-20 08:52:08  来源:igfitidea点击:

简介:在本教程中,您将学习如何使用MySQL锁定来协作会话之间的表访问。

锁是与表关联的标志。
MySQL允许客户端会话显式获取表锁,以防止其他会话在特定时间段内访问同一表。

客户端会话只能为其自身获取或释放表锁。
并且客户端会话无法获取或释放其他客户端会话的表锁。

在继续之前,让我们创建一个名为messages的表,以练习使用表锁定语句。

CREATE TABLE messages ( 
    id INT NOT NULL AUTO_INCREMENT, 
    message VARCHAR(100) NOT NULL, 
    PRIMARY KEY (id) 
);

MySQL LOCK TABLES语句

以下语句显式获取表锁:

LOCK TABLES table_name [READ | WRITE]

使用这种语法,您可以在LOCK TABLES关键字之后指定要锁定的表的名称。
此外,您可以指定锁的类型为READ或WRITE。

MySQL允许您通过在LOCK TABLES关键字之后指定具有您要锁定的锁定类型的表的逗号分隔名称列表来锁定多个表:

LOCK TABLES table_name1 [READ | WRITE], 
            table_name2 [READ | WRITE],
             ... ;

MySQL UNLOCK TABLES语句

要释放表的锁,请使用以下语句:

UNLOCK TABLES;

读锁

READ锁具有以下功能:

  • 可以通过多个会话同时获取表的READ锁。
    此外,其他会话可以从表中读取数据而无需获取锁。

  • 拥有READ锁的会话只能从表中读取数据,而不能写入。
    在释放READ锁定之前,其他会话无法将数据写入表。
    来自另一个会话的写操作将进入等待状态,直到释放READ锁为止。

  • 如果会话正常或异常终止,MySQL将隐式释放所有锁。
    此功能也与WRITE锁定有关。

让我们看一下在以下情况下READ锁的工作方式。

在第一个会话中,首先,连接到数据库并使用CONNECTION_ID()函数来获取当前的连接ID,如下所示:

SELECT CONNECTION_ID();

然后,将新行插入到消息表中。

INSERT INTO messages(message) 
VALUES('Hello');

接下来,在消息表中查询数据。

SELECT * FROM messages;

之后,使用LOCK TABLE语句获取一个锁。

LOCK TABLE messages READ;

最后,尝试在messages表中插入新行:

INSERT INTO messages(message) 
VALUES('Hi');

MySQL发出以下错误:

Error Code: 1099. Table 'messages' was locked with a READ lock and can't be updated.

因此,一旦获得了READ锁,就无法在同一会话中将数据写入表中。

让我们从另一个会话中检查READ锁定。

首先,连接到数据库并检查连接ID:

SELECT CONNECTION_ID();

接下来,从message表中查询数据:

SELECT * FROM messages;

然后,将新行插入到消息表中:

INSERT INTO messages(message) 
VALUES('Bye');

这是输出:

来自第二个会话的插入操作处于等待状态,因为第一个会话已在消息表上获取了READ锁,并且尚未释放。

从第一个会话开始,使用SHOW PROCESSLIST语句显示详细信息:

SHOW PROCESSLIST;

之后,返回到第一个会话,并使用UNLOCK TABLES语句释放锁。
从第一个会话释放READ锁后,将在第二个会话中执行INSERT操作。

最后,检查它的消息表数据,以查看第二个会话中的INSERT操作是否真正执行。

SELECT * FROM messages;

写锁

WRITE锁具有以下功能:

  • 持有表锁的唯一会话可以从表读取和写入数据。

  • 在释放WRITE锁定之前,其他会话无法从表读取数据或将数据写入表。

让我们详细了解WRITE锁的工作原理。

首先,从第一个会话获取WRITE锁定。

LOCK TABLE messages WRITE;

然后,将新行插入到消息表中。

INSERT INTO messages(message) 
VALUES('Good Moring');

有效。

接下来,从消息表中查询数据。

SELECT * FROM messages;

它也可以。

之后,从第二个会话尝试写入和读取数据:

INSERT INTO messages(message) 
VALUES('Bye Bye');

SELECT * FROM messages;

MySQL将这些操作置于等待状态。
您可以使用SHOW PROCESSLIST语句检查它。

SHOW PROCESSLIST;

最后,从第一个会话中释放锁。

UNLOCK TABLES;

您将看到第二个会话中执行的所有未决操作,下图说明了结果:

读与写锁

  • 读锁是"共享"锁,可以防止获取写锁,但不能获取其他读锁。

  • 写锁是"排他"锁,可防止其他任何形式的锁。

在本教程中,您学习了如何锁定和解锁表以配合会话之间的表访问。