文档章节

MqSql的加锁分析

c
 cpf2016
发布于 2016/08/03 23:01
字数 1628
阅读 24
收藏 0

(1)MVCC与基于锁的并发控制

             MySql的InnoDB引擎,实现的是基于多版本的并发控制协议:MVCC。

             MVCC最大的好处,即读不加锁,读写不冲突。在读多于写的应用中,读写不冲突是非常重要的,极大的增强了系统的并发性能。这也就是为什么,几乎所有的RDBMS都支持了MVCC。

             

(2)快照读与当前读

          1.快照读

                简单的select操作,属于快照读,不加锁(当然如果是Serializable隔离级别还是要加锁)

                如:select * from table where ?

 

          2.当前读

                包括特殊的读操作,插入、更新、删除操作,都属于当前读,需要加锁

                如:

                     select * from table where ? lock in share mode;

                     select * from table where ? for update;

                     insert into table values(...);

                     update table set ? where ?

                     delete from table where?

                  所有以上语句,都属于当前读,读取记录的最新版本。并且读取之后,还要保证其他并发事务不能修改当前记录,对读取的记录加锁。

                 其中,除了第一条语句,对读取记录加S锁(共享锁)以外,其他的操作,都加的是X锁(排他锁)

 

          3.为何插入、更新、删除操作都属于当前读?

                 更新操作的执行流程如下:

                

              从图中可以看到一个update操作的具体流程:

              1.update sql发送到mysql后,mysql server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并对记录加锁

              2.mysql server收到这条加锁的记录后,会再发起一个update请求,更新这条记录

              3.这条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止 。

              注意:针对一条当前读的sql,InnoDB与mysql server的交互,是一条条进行的,因此加锁也是一条条进行的。

                        先对一条满足条件的记录加锁,返回给mysql server,做一些DML操作;然后再读取下一条并加锁,直至读取完毕

 

(3)2PL:Two-Phase Locking

             传统的RDBMS加锁的一个原则就是2PL(二阶段锁)。

             简单地说就是锁操作分为2个阶段:加锁阶段与解锁阶段,并且保证加锁阶段与解锁阶段不相交。

                   

             从上图可以看出,2PL就是将加锁、解锁分为2个完全不相交的阶段:加锁阶段:只加锁不放锁,解锁阶段:只放锁不加锁

 

(4)隔离级别与加锁

           1.read uncommitted

               读未提交,不会使用,忽略

           2.read committed(RC)

               快照读不加锁

               当前读,RC隔离级别保证对读取到的记录加锁,但存在幻读情况

           3.repeatable read (RR)

               快照读不加锁

               当前读,RR隔离级别保证对读到的记录加锁,同时保证对读取的范围加锁,因此新的满足查询条件的记录不能够插入(间隙锁),因而不存在幻读情况

           4.serializable

               从MVCC退化为基于锁的并发控制。不区别快照读和当前读,所有的读操作均为当前读,读加读锁(S锁),写加写锁(X锁)

               serializable隔离级别下,读写冲突,因此并发度急剧下降,不建议使用。

 

(5)加锁分析

             因为快照读在RC、RR下都不加锁,所以我们不讨论快照读,而只讨论当前读的情况

             接下来以delete from t1 where id=10这条sql为例,来分析加锁的情况

            1.id主键+RC

                 这个组合最为简单。因为id为主键,where的条件为id=10,所以只需要在id=10的记录上加X锁即可

               

     

            2.id唯一键+RC

                 name为主键,id为唯一键,那么在RC隔离级别下,delete from t1 where id=10需要如何加锁呢?

                

                先对唯一索引树上id=10的记录加上X锁,然后因为id=10对应的是name=d,那么从主键索引上查找到name=d的记录,然后对这条记录加X锁。

 

            3.id非唯一键索引+RC

             

             此时在id的索引树上id=10的有2条记录,所以先对这2条记录加锁。

             然后因为name是主键,所以在主键索引上查找到name=b和name=d的记录,然后对这2条记录加锁

            4.id无索引+RC

                 因为id无索引,所以就只能全表扫描了,此时会对所有记录加X锁(但实际情况会优化)

                 

 

            5.id主键+RR

                 id列是主键,RR隔离级别,这条sql与在RC级别下一致,都是对这条记录加X锁

            6.id唯一键+RR

                 与RC下一致,也是先对唯一索引树上记录加X锁,然后对主键索引树上对应记录加X锁

            7.id非唯一键+RR

                 

               这与RC隔离级别下有很大差别,主要是多了一个gap锁,而且gap锁是加在记录之间,而不是加在记录之上

               gap锁有什么用呢?实际上这个gap锁就是RR隔离级别,这是相对于RC隔离级别而言,不会出现幻读的关键。

               gap锁锁住的位置,不是记录本身,而是2条记录之间的gap。所谓幻读,就是在同一个事务中,连续做两次当前读,比如select * from t1 where id =10 for update,出现了2次记录数量不一致的情况,就好像见到鬼了。

               那么如何保证两次当前读返回一致的记录数呢?那就需要根据where条件确定记录范围,然后保证在这个范围内,不会被其他事物插入新的、满足条件的记录。(举个例子:假如条件为select * from table id>5 and id <10,而表中只有id=7,id=8两条记录满足条件,如果有了gap锁,那么就会将id=6的左边和id=7的右边边界加上gap锁,这样如果其他事务要插入一条id=9的记录,就需要等待了)这就是gap锁的作用。

                           7.id无索引+RR

                              这种情况必须要进行全表扫描,因而需要首先需要对所有记录加X锁,并且为了防止幻读,对所有数据的间隙加上了gap锁

                              

                               此时全表被锁死,无法更新、删除、插入

                           8.serializable

                               读写全部加X锁

 

 

© 著作权归作者所有

共有 人打赏支持
c
粉丝 2
博文 631
码字总数 157379
作品 0
杭州
后端工程师
私信 提问
mysql zip install

NET HELPMSG 3534 问题:在安装MqSql的5.7.12版本时,在注册服务mysqld install MySQL --defaults-file="my-default.ini路径"后执行net start mysql,启动MySql失败。 根源:那是因为5.7版本...

小熊猫大暴走
05/23
0
0
Nova reboot 和 lock 操作 - 每天5分钟玩转 OpenStack(32)

前面 CloudMan 通过日志详细分析了 nova 的 launch, shut off 和 start 操作。 不知道大家现在是否已经掌握了日志分析的技能? 今天咱们就来检验一下。 本节讨论的是 nova 相对较简单的操作:...

CloudMAN
2016/05/11
289
3
MySQL 不同隔离级别加锁情况

对于MySQL 各种隔离级别的加锁情况分析的博客很多 但对 read uncommitted 这个级别的加锁情况分析总是一笔带过。 甚至美团的博客简述 read uncommitted 隔离级别不加任何锁。 但我分析下来确...

mark_rock
2017/03/26
88
1
mysql并发insert死锁问题——gap、插入意向锁冲突

问题描述 线上出现MySQL死锁报警,通过show engine innodb status命令查看死锁日志,结合异常代码,还原发生死锁的事务场景如下: 环境: mysql5.7,事务隔离级别REPEATABLE-READ 表结构 并发...

hebaodan
06/26
0
1
MySQL 加锁处理分析

MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题。本文,准备...

wangergui
2017/03/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

php获取客户端IP

php获取客户端IP 首先先阅读关于IP真实性安全的文章:如何正確的取得使用者 IP? 「任何從客戶端取得的資料都是不可信任的!」 HTTP_CLIENT_IP头是有的,但未成标准,不一定服务器都实现。 ...

DrChenXX
昨天
0
0
. The valid characters are defined in RFC 7230 and RFC 问题

通过这里的回答,我们可以知道: Tomcat在 7.0.73, 8.0.39, 8.5.7 版本后,添加了对于http头的验证。 具体来说,就是添加了些规则去限制HTTP头的规范性 参考这里 具体来说: org.apache.tom...

west_coast
昨天
1
0
刷leetcode第704题-二分查找

今天双十一买的算法书到货了,路上刷到有人说的这个题,借(chao)鉴(xi)一下别人的思路,这个是C++标准库里面的经典方法,思路精巧,优雅好品味 int search(int* nums, int numsSize, in...

锟斤拷烫烫烫
昨天
2
0
【分享实录】BANCOR算法详解及代码实现

1 活动基本信息 1)主题:【区块链技术工坊22期】BANCOR算法详解及代码实现 2)议题: BANCOR算法的特点和优劣势 BANCOR算法和举例 如何加入BANCOR.NETWORK交易所 如何开发自己的BANCOR去中心...

HiBlock
昨天
2
0
微信小程序(2)

开始看微信小程序的教程了。刚刚看完官方教程的视图层部分。这里摘录一些自己认为的部分关键点。 1.直接修改数值无法重新渲染,需要使用setData()方法; 2.列表渲染中:wx:key用于保持项目在...

MKjy
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部