Mysql事务隔离级别的误区(InnoDB为例)

1 问题引入

看下图:
在这里插入图片描述
        根据Mysql技术内幕:InnoDB引擎,不同事务隔离级别可以解决不同问题,分别是脏读,不可重复读(幻读),丢失更新,和上图不一致
        而不可重复读其实就是幻读(上述说两者有细微差别),丢失更新是业务层面的丢失(对同一银行账户进行余额查询并修改,导致最后结果不一致,后续有相关例子)

依稀记得,在大学期间的数据库教材Sql Server中学过这个知识点(如今找不到这本书),
这本书将不可重复读和幻读区别开,就和上图一样,而此文以mysql的InnoDB为例,介绍不同之处
个人理解:后续会介绍,此处只是为了全文的完整性
上述的那张图的来源就是,当没有范围锁机制且使用行级锁(InnoDB将范围锁加入到RR隔离级别中解决幻读问题)。
修改记录,对其加x锁就可避免(不可重复读);而插入则不能,因为插入的不是同一行记录,插入不会锁冲突(幻读)

2 不同级别的实现

1)先验知识

1)MVCC:读不加锁,读取的被锁住数据的历史快照版本数据,RC,RR级别读取的版本不一致,RC读取最新历史版本,RR读取事务开始前的那个版本。
2Next-key LockRecord Lock只锁住要操作的那个记录,而Next-key则锁住记录及其周边的记录
-----更具体的相关知识自行百度即可

        RC(Read-Commited),RR级别的事务隔离级别的默认读操作使用的是MVCC,即读不加锁,读取被锁住的数据的历史快照版本,且RR级别的MVCC才能解决后续的不可重复读(幻读)。

为什么RR的MVCC能解决幻读,因为不管其他事务如何修改,RR的读只读取自己事务开始前的那个版本的数据,故不会产生幻读

        故可知后续需要分需不需要对读操作加锁来讨论,当需要及时读取最新的数据时,需要对读数据进行加锁,这时候就不能使用MVCC来解决幻读了,需要Next-Key机制来解决

举例:事务1读取 >2 的数只有4,此时事务2插入一条数据5,
如果是一般的Record Lock,只锁住记录4,记录5照样可以插入;
而范围锁(NextKey)则锁住了(2,+)这个范围,记录5无法插入

2)实现

1Read UnCommited:脏读都解决不了,事务之间没有隔离性,不加任何锁

2Read Commited:
		i)不加锁:MVCC,读最新的历史数据,可以判断读取的数据是否已经提交
		ii)加锁:读加S(读完就放),加了写锁,就可以保证不出现脏读,因为只有事务提交了(事务不会回滚了),锁才会释放(读加锁可以读取到写修改的数据)
		
3Read Repeated:解决幻读问题
		i)不加锁:MVCC
		ii)加锁:读加s锁并保持到事务结束,写加x锁(一样);并使用Next-key Lock机制解决幻读
		(最开始的那张图的来源就是,没有范围锁机制,修改记录,对其加x锁就可避免;而插入则不能,因为插入的不是同一行记录,所以不会冲突,依旧可插入)
		
4)Serializable:解决更新丢失问题
		必须对事务中的读操作加X锁,使得其他事务阻塞,事务之间无法并发
				

下面举例说明丢失更新问题:

//一般业务都需要先读取余额,然后查看是否可以转账,在进行update操作
事务1:读取数据---------------------数据更新
事务2----------读取数据---------------------数据更新

这在数据库层面是没问题的,因为数据更新会加X锁,数据会是事务2修改的

但在业务层面,事务1转账1000,事务2转账2000,最终的结果是只转账了2000
对读操作也加X锁,事务1读取后,事务2就阻塞,当事务1转账1000完成后,事务2才进行转账2000

3 总结

InnoDB引擎:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43849906/article/details/121322313