MySQL Innodb存储引擎 事务隔离级别 锁 理解

隔离级别:

Read Uncommitted---读未提交: 其他事务对行的修改,对本事务可见。

Read Committed---读已提交: 其他已提交的事务对行的修改,对本事务可见。

Repeatable Read---可重复读:其他在本事务开始之前就已经已提交的事务对行的修改,对本事务可见。

Serializable---串行化的读:本事务中所有的读都加共享锁,直到本事务结束。

问题一:怎么做到的?

undo log在每次事务对行进行修改的时候,会在该行中保存一个属性,通过这个属性,能找到修改改行的事务提交时当前的系统版本号(也就是事务的最大id),并保存没修改之前的版本。所以一致性非锁定读会根据当前事务的隔离级别,去选择读取当前的行(读未提交),或者之前版本中最新的(由于行锁的存在,之前版本中最新的行信息对应的事务一定是已提交了的,这样才会释放掉行锁,下一个事务才能进来,把上一个事务修改完的行信息放到之前版本中)(读已提交),或者再往前,去找在本事务开始之前其他已提交的事务对行的修改(可重复读)。

问题二:可重复读级别下,会不会出现幻读(两次读出来的东西不同),以及真正的幻读是怎么回事?

根据上面的逻辑,可重复读不会读取本事务开始之后再提交的事务对行的修改,所以不会出现幻读。真正的幻读其实只有一种(或类似)情况:有一列(比如name)上有唯一索引,本事务根据name='c'去数据库里查,没有冲突,准备插入,但是在插入之前,别的事务插入了name='c'的行,这个时候本事务如果再插入,就会报错,这就像见鬼了一样:刚才我明明查到没有这一条的。

总结:其实innodb的隔离级别,说到底还是那个永恒的话题:怎样解决并发冲突,这个话题的解决在ConcurrentHashMap,copyOnWriteArrayList,ReadWriteLock等设计中都有体现。目的就是既保证并发安全,又保证效率。ConcurrentHashMap用hash的办法减小加锁颗粒度,用cas+无限循环的办法(其实是个乐观锁)避免使用ReentrantLock和Syncronized的重量级锁这样的大对象导致的浪费资源,以及使用自旋避免直接挂起线程导致内核态的切换。copyOnWriteArrayList用的是多版本快照,ReadWriteLock用的是读和写的共享互斥锁。这些东西在innodb的设计中都有体现,颗粒度的问题比如行锁代替表锁,共享互斥锁和多版本快照就不多说了。

问题三:undo脏页什么时候刷新到磁盘?

Innodb是把undo当做数据页对待,undo的同时写redo,那么这样就需要在脏页(数据页或者undo页)刷新到磁盘之前,刷新redo页,否则无法回滚。

原文地址:https://www.cnblogs.com/chuliang/p/9854260.html