程序员社区

MySQL系列教程 --- 27、MySQL中的表锁(读锁、写锁)

锁是一种与表相关联的机制,用于限制对表中数据的未授权访问。MySQL 允许客户端会话显式获取表锁以与其他会话合作访问表的数据。MySQL 还允许表锁定,以防止它在特定时间段内对同一表进行未经授权的修改。

MySQL 中的会话只能为自己获取或释放表上的锁。因此,一个会话不能为其他会话获取或释放表锁。需要注意的是,我们必须有 TABLE LOCK 和 SELECT 权限才能进行表锁定。

MySQL 中的表锁定主要用于解决并发问题。它将在运行事务时使用,即首先从表(数据库)读取值,然后将其写入表(数据库)。

MySQL为表提供了两种类型的锁,它们是:

READ LOCK:此锁允许用户仅从表中读取数据。

WRITE LOCK:此锁允许用户对表进行读取和写入操作。

需要注意的是,MySQL 中使用的默认存储引擎是 InnoDB。InnoDB 存储引擎不需要手动锁定表,因为 MySQL 自动对 InnoDB 表使用行级锁定。因此,我们可以在同一张表上同时做多个事务来进行读写操作,而无需相互等待。所有其他存储引擎在 MySQL 中使用表锁定。

在了解表锁定概念之前,首先,我们将使用如下语句创建一个名为“ info_table ”的新表:

CREATE TABLE info_table (   
    Id INT NOT NULL AUTO_INCREMENT,   
    Name VARCHAR(50) NOT NULL,   
    Message VARCHAR(80) NOT NULL,  
    PRIMARY KEY (Id)   
);  

MySQL LOCK TABLES 语句

以下是允许我们显式获取表锁的语法:

LOCK TABLES table_name [READ | WRITE];  

在上面的语法中,我们在LOCK TABLES关键字之后指定了我们想要获取锁的表名。我们可以指定锁定类型,READ 或 WRITE。

我们还可以通过使用带有锁定类型的逗号分隔表名称列表来锁定 MySQL 中的多个表。请参阅以下语法:

LOCK TABLES tab_name1 [READ | WRITE],   
            tab_name2 [READ | WRITE],...... ;  

MySQL UNLOCK TABLES 语句

以下是允许我们MySQL 中的表释放锁的语法:

mysql> UNLOCK TABLES;  

锁类型

让我们详细了解锁类型。

读锁

以下是READ锁的特点:

  • 同时,MySQL 允许多个会话获取一个表的 READ 锁。并且所有其他会话都可以在不获取锁的情况下读取该表。
  • 如果会话持有表上的 READ 锁,则它们无法对其执行写操作。这是因为 READ 锁只能从表中读取数据。未获得 READ 锁的所有其他会话无法在不释放 READ 锁的情况下将数据写入表中。写操作进入等待状态,直到我们还没有释放 READ 锁。
  • 当会话正常或异常终止时,MySQL 会隐式释放对表的所有类型的锁。此功能也与 WRITE 锁相关。

让我们举一个例子来看看在给定场景下 READ 锁是如何在 MySQL 中工作的。我们将首先连接到数据库并使用CONNECTION_ID()函数,该函数在第一个会话中给出当前连接 ID,如下所示:

mysql> SELECT CONNECTION_ID();  

请参阅以下输出:

file

接下来,我们将使用以下语句在info_table 中插入几行:

mysql> INSERT INTO info_table (name, message)   
VALUES('Peter', 'Hi'),  
('Joseph', 'Hello'),  
('Mark', 'Welcome');  

现在,使用以下语句验证表中的数据:

mysql> SELECT * FROM info_table;  

我们应该看到如下输出:

file

现在,我们将执行 LOCK TABLE 语句来获取对表的锁:

mysql> LOCK TABLE info_table READ;  

之后,我们将尝试向 info_table 中插入一条新记录,如下所示:

mysql> INSERT INTO info_table (name, message)   
VALUES ('Suzi', 'Hi');  

我们将得到以下输出,其中 MySQL 发出以下消息“Table 'info_table' was locked with a READ lock and can't be updated”

file

因此,我们可以看到,一旦获得了对表的 READ 锁,我们就不能在同一个会话中向表中写入数据。

现在,我们将检查 READ 锁如何在不同的会话中工作。首先,我们将连接到数据库并查看连接 id:

file

接下来,我们将从返回输出的 info_table 中查询数据,如下所示:

file

然后,将一些行插入到该表中,如下所示:

mysql> INSERT INTO info_table (name, message)   
VALUES ('Stephen', 'Hello');  

我们应该看到如下输出:

file

在上面的输出中,我们可以看到来自第二个会话的插入操作处于等待状态。这是由于 READ 锁,该锁已被第一个会话在表上获取并且尚未释放。

我们可以在第一个会话中使用SHOW PROCESSLIST语句查看有关它们的详细信息。请参阅以下输出:

file

最后,我们需要在第一个会话中使用UNLOCK TABLES语句来释放锁。现在,我们可以在第二个会话中执行 INSERT 操作。

写锁

以下是 WRITE 锁的特点:

  • 会话持有表的锁并且可以从表中读取和写入数据。
  • 它是唯一通过持有锁访问表的会话。并且在释放 WRITE 锁之前,所有其他会话都无法访问该表的数据。

让我们举一个例子来看看 WRITE 锁是如何在给定场景下的 MySQL 中工作的。在第一个会话中,我们将使用以下语句获取 WRITE 锁:

mysql> LOCK TABLE info_table WRITE;  

然后,我们将在 info_table 中插入一条新记录,如下所示:

mysql> INSERT INTO info_table (name, message)   
VALUES ('Stephen', 'How R U'

上面的说法奏效了。现在,我们可以使用 SELECT 语句验证输出:

file

同样,我们将尝试从第二个会话访问(读/写)表:

INSERT INTO info_table (name, message)   
VALUES ('George', 'Welcome');  

SELECT * FROM info_table;  

我们可以看到这些操作都进入了等待状态。使用 SHOW PROCESSLIST 语句查看有关它们的详细信息:

file

最后,我们将从第一个会话中释放锁。现在,我们可以执行挂起的操作。

读与写锁

  • 读锁类似于“共享”锁,因为多个线程可以同时获取它。
  • 写锁是一种“排他”锁,因为另一个线程无法读取它。
  • 我们不能同时在表上提供读写锁。
  • 读锁的优先级低于写锁,可确保尽快进行更新。
赞(0) 打赏
未经允许不得转载:IDEA激活码 » MySQL系列教程 --- 27、MySQL中的表锁(读锁、写锁)

一个分享Java & Python知识的社区