MySQL锁总结
本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/78
参考了何登成老师文章的结构MySQL 加锁处理分析,中间又加了一些自己觉得需要考虑的情况。
分析本session的加锁方式
- 系统的隔离级别是什么?是RC还是RR?
- 判断SQL的加锁类型,是共享锁还是排他锁?
- SQL的执行计划是什么,涉及到索引了吗?
- 如果用到了索引,该索引是主键索引,还是二级索引?
- 如果是二级索引,该索引是唯一索引吗?
分析其他并行session是否阻塞
- 先按上述方式分析本session的加锁方式
- 遍历扫描记录上的所有锁,包括等待的锁,有发生状态冲突时,就进入锁等待队列。
- 进入锁等待队列之后,判断死锁并选择受害者。(利用wait-for-graph,可以参考篇首链接内的死锁部分)
- 前面的事务释放锁之后,按顺序获取锁。
数据准备
mysql> show create table test\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL default '0',
`v1` int(11) default NULL,
`v2` int(11) default NULL,
`v3` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `v3` (`v3`),
KEY `idx_v1` (`v1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> select * from test;
+----+------+------+----+
| id | v1 | v2 | v3 |
+----+------+------+----+
| 0 | 4 | 15 | 0 |
| 1 | 1 | 0 | 1 |
| 2 | 3 | 1 | 2 |
| 3 | 4 | 2 | 3 |
| 5 | 5 | 9 | 5 |
| 7 | 7 | 4 | 7 |
| 8 | 7 | 3 | 8 |
| 10 | 9 | 5 | 10 |
| 30 | 8 | 15 | 30 |
+----+------+------+----+
9 rows in set (0.00 sec)
主键为id,唯一索引v3,二级普通索引v1。
以下所举的例子中,表中的数据均为上面select查询到的数据。
查询主键查找 + RC
| session1 | session2 |
|---|---|
| begin | |
| begin | |
| update test set v1=100 where id=10; | |
| select * from test where id=10 for update; 阻塞 | |
| select * from test where id=9 for update; Empty set (0.00 sec) | |
| select * from test where id=11 for update; Empty set (0.00 sec) |
结论:此时只在对应的主键记录上加X锁即可。
查询唯一索引查找 + RC
| session1 | session2 |
|---|---|
| begin | |
| begin | |
| update test set v2=100 where v3=10; | |
| select * from test where id=10 for update; 阻塞 | |
| select * from test where v3=10 for update; 阻塞 | |
| select * from test where v2=10 for update; 阻塞 | |
| select * from test where id=9 for update; Empty set (0.00 sec) |
为什么会在主键上加X锁呢?假设此时有个并发sql:delete from test where id=10,那么并发的update 就会感知不到delete 语句的存在,违背了同一记录上的更新/删除需要串行执行的约束。
为什么select * from test where v2=10 for update;会阻塞?因为v2上没有索引,MySQL判断走全表扫描对每个记录加X锁,但是表中id=10的记录有X锁了,两者不兼容,所以阻塞。
注意session1中update语句首先对表加了IX意向锁,session2判断表有IX锁,说明底层的记录有session在加X锁,所以直接阻塞。这样的花MySQL不用深入底层的每条记录,去判断每条记录是否有IX锁,这样太耗时了。(详细见MySQL 锁基础意向锁部分)
结论:此时需要加两个X锁,一个是唯一索引上v3=10的记录,还有聚簇索引上id=10的元组。
查找非唯一索引 + RC
同上。区别是对所有满足SQL查询记录的加X锁,同时对应的主键也都加X锁。
查询无索引 +RC
| session1 | session2 |
|---|---|
| begin | |
| begin | |
| update test set v2=1000 where v2=15; | |
| select * from test where v1=4 for update; 阻塞 |
因为查询不能用到索引,只能进行全表扫描,对聚簇索引上的所有记录都加了X锁(不是加表锁,也不是在满足条件的记录上加行锁)。
为什么不是在满足条件的记录上加锁呢?如果一个条件无法通过索引快速过滤,那么存储引擎层面就会将所有记录加锁后返回,然后由MySQL Server 层进行过滤。因此也就把所有的记录都锁上了。
但是在5.1及更新的版本中,MySQL会在Server层过滤后,将不符合条件的记录全部释放锁,但是在更早期的版本中,MySQL只有在事务提交之后才释放锁。(高性能MySQL中文版第三版 P181)
结论:每条记录都加上X锁。
查询主键查找 + RR
与查询主键查找 + RC一致。
查询唯一索引查找 + RR
与查询唯一索引查找 + RC一致。
查找非唯一索引 + RR
| session1 | session2 |
|---|---|
| begin | |
| begin | |
| update test set v2=1000 where v1=7; | |
| update test set v1=6 where v1=9; 阻塞 | |
| update test set v1=8 where v1=9; 阻塞 | |
| update test set v1=5 where v1=9; 阻塞 | |
| update test set v1=9 where v1=9; Query OK, 1 row affected (0.00 sec) |

与RC模式不同,RR模式要求不可幻读,即在同一个事务中,连续两次当前读 ,那么这两次当前读返回的是完全相同的记录。这里的session1的update test set v2=1000 where v1=7就是当前读,为了保证不出现幻读,需要在v1=7的两端加入GAP锁,保证其他事务不能同时在这个范围内插入数据。
为什么唯一索引不用加GAP锁?因为唯一索引的唯一性保证了两次当前读一定会返回一条数据而不是两条,因为唯一性嘛。所以一定·不会有新的数据插入进来。但是如果第一次当前读update test set v2=100 where v3=10没有符合条件的查询记录呢?MySQL还是会加GAP锁,来保证这一区间不会有数据插入。
但是这个个人不理解的是为什么GAP的两端点都是闭合的?即更新v1=5和v1=8都会阻塞?
查询无索引 + RR
这个综合以上几个例子比较好理解:会对每一个记录加X锁,其次,聚簇索引每条记录间的间隙(GAP),也同时被加上了GAP 锁。
更复杂的例子
参考更复杂的例子
MySQL首先在索引层加GAP锁,再在聚簇索引对应的主键加X锁,再在server层做过滤。而不是先过滤,再在聚簇索引主键加X锁。
总结
- 对于加锁读,InnoDB在它scan到的所有索引记录上加锁,而不管这条记录是否符合where条件。
- GAP锁的唯一作用封禁其他并行事务的写入,防止幻读。所以判断是否sql是否加GAP锁的最好方式就是判断sql语句是否需要防止幻读。
- 对于非唯一索引的range查询,range_read(start_key,end_key)来说:
- 通过索引找到第一条满足条件的记录
- 顺序向后扫描,途中碰到的记录,加LOCK_ORDINARY(锁记录及之前的GAP)
- end_key定位不满足条件的第一条记录,退出
| where条件 | 定位条件 | 终止条件 | 加锁范围 |
|---|---|---|---|
| ID < X | infinum | X | (infinum,X] |
| ID <= X | infinum | X的下一条记录 | (infinum,X的下一条记录] |
| ID > X | X的下一条记录 | maxnum | (X,maxnum] |
| ID >= X | X | maxnum | [X,maxnum] |
参考资料:
http://hedengcheng.com/?p=771
http://blog.sina.com.cn/s/blog_a1e9c7910102vnrj.html
MySQL锁总结的更多相关文章
- mysql锁
锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有数 ...
- Mysql锁初步
存储引擎 要了解mysql的锁,就要先从存储引擎说起. 常用存储引擎列表如下图所示: 最常使用的两种存储引擎: Myisam是Mysql的默认存储引擎.当create创建新表时,未指定新表的存储引擎时 ...
- mysql锁表机制及相关优化
(该文章为方便自己查阅,也希望对大家有所帮助,转载于互联网) 1. 锁机制 当前MySQL支持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁,BDB 表支持页级锁,InnoD ...
- MySQL锁系列3 MDL锁
http://www.cnblogs.com/xpchild/p/3790139.html MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构 ...
- 01 MySQL锁概述
锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O 等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所有 ...
- Mysql锁机制介绍
Mysql锁机制介绍 一.概况MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...
- MySQL锁等待分析【2】
MySQL锁等待分析[1]中对锁等待的分析是一步一步来的.虽然最后是分析出来了,可是用时是比较长的:理清各个表之间的关系后,得到如下SQL语句,方便以后使用 select block_trx.trx_ ...
- MySQL锁与MVCC
--MySQL锁与MVCC --------------------2014/06/29 myisam表锁比较简单,这里主要讨论一下innodb的锁相关问题. innodb相比oracle锁机制简单许 ...
- Mysql锁机制--并发事务带来的更新丢失问题
Mysql 系列文章主页 =============== 刚开始学习 Mysql 锁的时候,觉得 Mysql 使用的是行锁,再加上其默认的可重复读的隔离级别,那就应该能够自动解决并发事务更新的问题.可 ...
随机推荐
- ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证
ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...
- Zabbix 3.0 部署监控 [二]
一.添加监控主机及设置 1.创建主机 Agent可以干一些SNMP无法干的事情,例如自定义监控项 snmp相关文章:http://www.abcdocker.com/abcdocker/1376 ...
- 作为新手,SEO要避免的五大误区
越来越多人在做网站的时候关注的不是网站的界面,而是网站的seo排名.Seo其实没有我们相信中的那么简单,特别对于新手,在实际操作过程中很容易遇到一些误区,今天我们简单说说新手要避免的五大seo误区. ...
- 【转】Cmder--Windows下命令行利器
原文链接:https://www.cnblogs.com/zqzjs/archive/2016/12/19/6188605.html cmder cmder是一个增强型命令行工具,不仅可以使用wind ...
- 《Linux命令行与shell脚本编程大全》第二十六章 一些有意思的脚本
26.1 发送消息 26.1.1 功能分析 1.确定系统中都有谁 $who 给出的信息包括用户名 用户所在终端 用户登入系统的时间 2.启用消息功能 用户可以禁止别人给我发消息,所以需要先检查一下是否 ...
- JAVA IO分析一:File类、字节流、字符流、字节字符转换流
因为工作事宜,又有一段时间没有写博客了,趁着今天不是很忙开始IO之路:IO往往是我们忽略但是却又非常重要的部分,在这个讲究人机交互体验的年代,IO问题渐渐成了核心问题. 一.File类 在讲解File ...
- 最近整理AI相关感想
前言 目前笔者致力于 在AI 开发研究,四大平台里,百度AI 提供 的开发者资料是最全,开发的友好度也是最高的,很多都已经集成在SDK中,支持许多语言体系. 其实 作为公司层面的考虑,针对技术的研究出 ...
- 初识java这个小姑娘(三)
说烂了的面向对象 我要说的面向对象,其实是一个我自己都觉的有点恶心的东西. 它是java语言入门如此初级的一个概念.作为一个老鸟,你可以吐口水给我,我可以把它们擦干,但作为总结还得说一说. 因为对于一 ...
- 指尖上的电商---(4).net开发solr
这一节我们看下如何把查询数据放到server端存储,这里我们须要使用client工具来操作与服务端数据打交道,网上有好多基于.NET开发的SOLRclient,我们这里选择easynet.solr,非 ...
- Intent及IntentFilter具体解释
Intent用于启动Activity, Service, 以及BroadcastReceiver三种组件, 同一时候还是组件之间通信的重要媒介. 使用Intent启动组件的优势 1, Intent为组 ...