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;
三、MySQL 锁类型
读锁(Read Lock)
以下是 读锁(Read Lock)的特点:
- 同时,MySQL 允许多个会话获取一个表的 读锁(Read Lock)。并且所有其他会话可以在不获取锁的情况下读取表。
- 如果会话持有表上的 READ 锁,则它们不能对其执行写操作。这是因为 读锁(Read Lock)只能从表中读取数据。所有其他未获取 读锁(Read Lock)的会话都无法在不释放 READ 锁的情况下将数据写入表中。写操作进入等待状态,直到我们没有释放 读锁(Read Lock)。
- 当会话正常或异常终止时,MySQL 会隐式释放对表的所有类型的锁。此功能也与 WRITE 锁相关。
让我们举个例子来看看在给定场景下 读锁(Read Lock)是如何在 MySQL 中工作的。我们将首先连接到数据库并使用CONNECTION_ID()函数在第一个会话中给出当前连接 ID,如下所示:
mysql> SELECT CONNECTION_ID();
请参阅以下输出:
接下来,我们将使用以下语句在info_table中插入几行:
mysql> INSERT INTO info_table (name, message)
VALUES('Peter', 'Hi'),
('Joseph', 'Hello'),
('Mark', 'Welcome');
现在,使用以下语句将数据验证到表中:
mysql> SELECT * FROM info_table;
我们应该看到如下输出:
现在,我们将执行 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"。
因此,我们可以看到,一旦获得了对表的 READ 锁,我们就无法在同一个会话中将数据写入表。
现在,我们将检查 READ 锁如何在不同的会话中工作。首先,我们将连接到数据库并查看连接 ID:
接下来,我们将从返回输出的 info_table 中查询数据,如下所示:
然后,在该表中插入一些行,如下所示:
mysql> INSERT INTO info_table (name, message)
VALUES ('Stephen', 'Hello');
我们应该看到如下输出:
在上面的输出中,我们可以看到来自第二个会话的插入操作处于等待状态。这是由于第一个会话已经在表上获得了 READ 锁,并且尚未释放。
我们可以在第一个会话中使用SHOW PROCESSLIST语句查看有关它们的详细信息。请参阅以下输出:
最后,我们需要在第一个会话中使用UNLOCK TABLES语句来释放锁。现在,我们可以在第二个会话中执行 INSERT 操作。
写锁(Write Lock)
以下是 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 语句验证输出:
同样,我们将尝试从第二个会话访问(读/写)表:
INSERT INTO info_table (name, message)
VALUES ('George', 'Welcome');
SELECT * FROM info_table;
我们可以看到这些操作都进入了等待状态。使用 SHOW PROCESSLIST 语句查看有关它们的详细信息:
最后,我们将从第一个会话中释放锁。现在,我们可以执行挂起的操作。
四、读锁 与 写锁的区别
- 读锁类似于“共享”锁,因为多个线程可以同时获取它。
- 写锁是“独占”锁,因为另一个线程无法读取它。
- 我们不能同时在表上提供读写锁。
- 读锁的优先级低于写锁,这样可以确保尽快进行更新。
热门文章
优秀文章