Mysql进阶之路(六)--- Mysql事务隔离机制详述(锁原理总结)

引言:

1.不可重复读和幻读的区别

很多人容易搞混不可重复读和幻读,确实这两者有些相似。但不可重复读重点在于update和delete,而幻读的重点在于insert。

不可重复读:事务A重复读取同一条数据,在读取的同时事务B修改并提交了这个条数据,那么A再读取的时候就会发生不一致。
幻读 :如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,

幻读不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。但是MySQL 在REPEATABLEREAD(默认隔离级别)就解决了幻读问题。

2.“读”与“读”的区别

事务的隔离级别其实都是对于读数据的定义,但到了这里,就被拆成了读和写两个模块来讲解。这主要是因为MySQL中的读,和事务隔离级别中的读,是不一样的。我们且看,在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,是不及时的数据,不是数据库当前的数据!这在一些对于数据的时效特别敏感的业务中,就很可能出问题。对于这种读取历史数据的方式,我们叫它快照读 (snapshot read),
而读取数据库当前版本数据的方式,叫当前读 (current read)。

很显然,在MVCC中:

快照读:就是select
select * from table …;

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁。
在这里插入图片描述

事务的隔离级别实际上都是定义了当前读的级别,MySQL为了减少锁处理(包括等待其它锁)的时间,提升并发能力,引入了快照读的概念,使得select不用加锁。而update、insert这些“当前读”,就需要另外的模块来解决了。

写(“当前读”)

事务的隔离级别中虽然只定义了读数据的要求,实际上这也可以说是写数据的要求。上文的“读”,实际是讲的快照读;而这里说的“写”就是当前读了。
为了解决当前读中的幻读问题,MySQL事务使用了Next-Key锁。

READ COMMITiED(读已提交)级别下的锁的详解

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可重复读(REPEATABLE READ)级别下锁的的详解

注:行锁防止别的事务修改或删除,GAP锁防止别的事务新增,行锁和GAP锁结合形成的的Next-Key锁共同解决了RR级别在写数据时的幻读问题。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果使用的是没有索引的字段,那么会给全表加入gap锁(锁住表中的所有记录,但是不属于表锁,而是行级锁。就是范围有点大。。。)。同时,它不能像上文中行锁一样经过MySQL Server过滤自动解除不满足条件的锁,因为没有索引,则这些字段也就没有排序,也就没有区间。除非该事务提交,否则其它事务无法插入任何数据。

思考:mysql可重复读(REPEATABLE READ)级别下为什么是部分解决幻读?

1. mysql中默认的隔离级别是可重复读 ,如何解决呢?

1:当前读:给改条数据加锁(悲观锁),即读取的时候就加锁,防止其他事务读取该数据().它能保证读取的都是最新数据
2:快照读:mvcc,多版本并发控制,详细的原理就不说了,它使得读写不冲突,由于读的都是事务的当前版本的数据,因此重复读也不会发现数据被修改。
在mysql种这两种方式的体现就是加锁和不加锁
普通查询不加锁使用快照读
如果在事务中出了查询外还有其他增加修改操作那么久要手动加锁实现当前读

2. 是否mvcc就解决了幻读呢?

一定程度上可以这么说,因为它保证事务中多次读取不会产生新的记录。
但是我们如果在事务中进行了插入操作,是否就能保证这条记录在插入时不存在呢?这点是不能保证的,这也是快照读的弊端。因此如果我们要保证操作安全就要手动加锁,如 select name from student where id >= 0 for update…,或者使用串行化的隔离级别。

发布了45 篇原创文章 · 获赞 3 · 访问量 2332

猜你喜欢

转载自blog.csdn.net/weixin_44046437/article/details/98965681
今日推荐