MySQL 锁

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 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)


转载地址:http://blog.csdn.net/signmem/article/details/7689157

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
SQL 存储 关系型数据库
【MySQL 数据库】11、学习 MySQL 中的【锁】
【MySQL 数据库】11、学习 MySQL 中的【锁】
76 0
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL】一文带你搞懂MySQL中的各种锁
【MySQL】一文带你搞懂MySQL中的各种锁
59 0
|
2月前
|
存储 SQL 关系型数据库
MySQL - 深入理解锁机制和实战场景
MySQL - 深入理解锁机制和实战场景
|
3月前
|
存储 监控 关系型数据库
mysql中的锁及其作用
mysql中的锁及其作用
33 0
|
1月前
|
存储 关系型数据库 MySQL
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
163 0
|
3月前
|
SQL 关系型数据库 MySQL
|
2月前
|
SQL 关系型数据库 MySQL
Mysql事务隔离级别和锁特性
Mysql事务隔离级别和锁特性
|
8天前
|
关系型数据库 MySQL 数据库
MySQL锁三部曲:临键、间隙与记录的奇妙旅程
MySQL锁三部曲:临键、间隙与记录的奇妙旅程
18 0
|
1月前
|
SQL 关系型数据库 MySQL
MySQL中的锁(简单)
MySQL中的锁(简单)
|
2月前
|
存储 关系型数据库 MySQL
mysql的锁机制实现原理
mysql的锁机制实现原理