一、前提
首先我们应该先明确 Mysql的四种隔离级别和四种对应的现象
- 隔离级别:
读未提交、读已提交、可重复读、串行化 - 现象:
脏读、丢失修改、不可重复读、幻读
二、先说结论
读提交和可重复读都是一种隔离级别,可重复读解决了读提交本身未解决的 关于同一事务多次读取同一记录不一致的问题
怎么解决的?
对比记忆:
在读提交中: 事务A第一次读取数据,事务B修改同一数据但并未提交,事务A第二次读取数据,此时事务A读取数据并没有变化,然后将事务B提交,事务A第三次读取数据,才能读到数据的修改。
在可重复读中: 事务A第一次读取数据,事务B修改同一数据但并未提交,事务A第二次读取数据,此时事务A读取到的数据仍是修改之前的结果,然后将事务B提交,事务A第三次读取数据,(区别来了!)此时事务A读取到的数据仍然没有变化。 就是说在事务A提交之前,即使事务B修改并提交了数据,事务A读取的结果也没有任何变化,所以才会可重复读;
说白话:
读提交在事务A提交之前,可以读到事务B修改并提交的数据
可重复读隔离级别下,事务A提交之前,无论事务B怎么修改怎么提交,读到的都是一样的数据。除非事务A也提交了,才会读到事务B作出的更改。
三、讨论分析
在明确前提定义之后,我们开始讨论;(具体不明白定义的朋友,我会将定义贴到文末)
首先最低的隔离级别是读未提交 该级别的开销小,并发量高,但是会带来我们所说的脏读现象 ——也就是事务A可以读取到事务B未提交的数据,也就是脏数据。
那么我们为了解决脏读 这一现象,出现了下一隔离级别读已提交 ——只能读到事务B提交之后的数据,在提交之前所做的修改,事务A是读不到的(不可见的)。
所以,在我们只能读到提交的数据之后,便出现了第三种现象,即在事务A开启后多次读取同一数据,在多次读取中间,事务B对数据进行了修改然后提交,提交之后事务A再读,导致事务A结束之前多次读取的数据不同,所谓的不可重复读(这个是现象)。
解决不可重复读这一现象,需要用到下一隔离级别 这个隔离级别叫做 可重复读。但是可重复读仍然会有遗留现象,即幻读——当事务A在读取某个范围内记录时,事务B在该范围内插入了新的记录。
最终,解决幻读就用到了串行化这一隔离级别,通过强制事务串行之行,避免幻读问题,他会在读取的每一行数据上加锁🔒,所以会导致大量的超时和锁征用问题。
InnoDB和XtraDB数据引擎用到了MVCC(多版本并发控制协议,读不加锁读写不冲突,可以了解一下通过隐藏列、undolog指针和ReadView实现)。锁方面解决幻读用到了 next-key-lock,相当于间隙锁和记录锁,不但会锁住一个范围,还会锁住记录本身。
四、 隔离级别和现象的定义:
READ UINCOYNITTED (读未提交)(很少用)
在READ UNCONMITTED 级别,事务中的修改,即使没有提交,对其他事务也都是可见
的。事务可以读取未提交的数据,这也被称为胜读 (Dirty Read)。这个级别会导致很多问题,从性能上来说,READ UNCONNIITTED 不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。
READ COMMITTED (提交读)
大多数数据库系统的默认隔离级别都是 READ COMMITTED (但 MysQL 不是)。READ COMMITTED 满足前面提到的隔高性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级別有时候也叫做不可重复读 (nonrcpcatable read),因为两次执行同样的查询,可能会得到不一样的结果。
REPEATABLE READ(可重复读)
REPEATABLE READ 解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom Read) 的向题。所谓幻谈,指的是当某个事务在该取某个范国内的记录时,另外一个事务又在该范围内插人了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行 (Phantom Row)。IanoDB 和XtraDB 存储引擎通过多版本并发控制 (MVCC, Multiversion Concurrency Control)解决了幻读的问题。
SERIALIZABLE(可串行化)
SERIALIZABLE 是最商的隔离级别。它通过强制事务串行执往,避免了前面说的幻读的问题。简单来说,SERIALIZABLE 会在读取的每一行数据上都加锁,所以可能导致大量的超时和领争用的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。
脏读
当事务A访问数据,此时事务B对同一数据进行修改,在事务B提交之前事务A仍然可以读取到事务B修改的数据;
丢失修改
当事务A修改数据,事务B在之后修改数据,那么事务A修改的数据结果也将会丢失,也就是最后只能查询到B修改的数据;
不可重复读
事务A读取数据,由于并发事务B对数据进行修改然后提交,导致的事务A再次读取,两次读取的结果不相同的现象。
幻读
事务A读取数据后,并发事务B插入或删除数据,导致后来事务A查询的结果与第一次事务A查询结果不同的现象。和前者的区别是不可重复读注重事务B对原数据的修改,而幻读是注重与事务B对原数据的增加或删除,注重于记录条数增加减少。