1、隔离级别的种类
RU:未提交读
RC:读提交
RR:可重复读 (默认)
Series:串行化
2、锁的种类
行锁,gap lock, next-key lock
共享锁,排他锁,意向共享锁,意向排他锁,插入意向锁
意向锁(插入意向锁不包括)之间互相兼容,可以说意向锁就是为了提高锁判断的效率的。两个事务都对同一个表加意向排他锁,也就是两个事务都是修改数据,那么底层的行锁会去再判断。而意向锁最大的意义是:当一个事务要对一个表加排他锁或者是共享锁时,如果没有意向锁的机制,那么他需要去看表里面是否每一行都被加了共享或者排他锁。
3、当前读和快照读
当前读:每次读都加锁,不允许其他事务对数据进行修改。比如update,delete, select for update ,select in share mode.读的是最新数据。也叫一致性锁定读。
快照读:读的是历史版本。就是通过mvcc实现的。也就一致性非锁定读。
4、MVCC
mvcc最大的好处是读不加锁。提高了系统的并发性。同时MVCC也能解决脏读的问题。mvcc在RC和RR级别下也是不同的。RC级别下,读取的是最新提交的记录,未提交的事务数据不读。能避免脏读。RR级别下,只读取事务开始时的快照,所以能够避免不可重复读。
实现原理:
在InnoDB中,会在每行数据后添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。 在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。 在可重读Repeatable reads事务隔离级别下:
SELECT时,读取创建版本号<=当前事务版本号,删除版本号为空或>当前事务版本号。
INSERT时,保存当前事务版本号为行的创建版本号。
DELETE时,保存当前事务版本号为行的删除版本号。
UPDATE时,插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行。
通过MVCC,虽然每行记录都需要额外的存储空间,更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,大多数读操作都不用加锁,读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,也只锁住必要行。
5、不同隔离级别是如何实现的
RU:
为什么会出现脏读?
首先可以确定在RU级别 写是肯定加排他锁的,为什么出现脏读?因为数据库事务的数据对于其他事务都是可见的,只不过不同的隔离级别对其他事务写入的数据做了可见性过滤。比如RC和RR 级别通过MVCC来做。而Serializable是串行化的。所以RU隔离级别下,能直接读到其他活事务提交的数据并且没有做任何过滤,所以会出现脏读。
RC:
RC主要避免脏读,MVCC实现的,只能提交的数据。
RR:
RR隔离级别能够防止幻读是通过两个手段达到的。
这里区分两种场景,当前读和非当前读。非当前读是通过MVCC来保证的。RR级别的MVCC和RC级别的MVCC不一样,RR级别只读取事务开始时的快照。而RC是读取最新的快照(快照读不加gap锁,所以其他事务是可以继续插入的,只不过在读的时候进行了屏蔽或者说是过滤)。当前读,RR级别通过加next-key lock来避免幻读。这里加了gap锁后,由于插入会加插入意向锁,而插入意向锁和gap锁是不兼容的,当存在gap锁时,是不允许加插入意向锁的。
Serializable:
普通的select都加锁,完全串行化了
6、几个例子
rc隔离级别下,如果select for update不会加gap锁,其他事务是可以插入的。但是rr级别下是不可以插入的。
参考文章:
http://blog.sae.sina.com.cn/archives/2127 讲的非常好了
https://blog.youkuaiyun.com/silyvin/article/details/79320398 脏读怎么出现的?
https://www.aneasystone.com/archives/2017/11/solving-dead-locks-two.html insert intention lock
https://blog.youkuaiyun.com/sun_ashe/article/details/82683296 insert隐式锁
https://chenguoji.com/2019/05/21/mysql-dao-di-shi-zen-me-jie-jue-huan-du-de/ RR级别是如何防治幻读的讲解