浅谈MySQL的四种隔离级别
众所周知,MySQL的四种隔离级别分别是
- READ UNCOMMITTED (读未提交)
- READ COMMITTED (读已提交)
- REPEATABLE READ (可重复读)
- SERIALIZABLE (串行化)
从上到下,隔离的级别越来越高,但性能越来越差。MySQL为什么要有隔离性呢?就要引出实际业务中可能出现的问题。
脏读
简单理解就是当前同时存在2个及以上的事务,即并发环境下,事务1读取到了事务2中未提交的数据,比如事务2修改user
表age
字段从1改为25,在事务2还未提交时,这条数据就被事务1读到了。
有什么问题?
假如事务2修改age
为25后,因为某些原因回滚了事务,那么事务1读到的25就是“脏数据”,比如事务1继续拿这个“脏数据”做了一些操作,那么后续的操作都是不合理的。.
READ UNCOMMITTED (读未提交) 无法解决脏读的问题
不可重复读
这就引出了 READ COMMITTED (读已提交),read commited 顾名思义就是在一个事务中(只)能读到另一个事务已提交的数据。还是上面的例子,同时存在两个事务,事务1中将age
字段从1改为25,在事务1没有提交之前,事务2中查询到的age
都是1。直到事务1提交了,事务2再次读取的age
才是25;如此一来就解决了“脏读” 的问题,但是这样就完美了吗?
有什么问题?
仔细考虑我们发现,事务2在一个事务周期的不同时刻,读取的age
字段是不一样的。在事务1未提交前,读取到的是1,事务1提交后,读取的到的是25。这就是不可重复读。
READ COMMITTED (读已提交) 无法解决不可重复读的问题
幻读
为了解决不可重复读的问题,自然引出 REPEATABLE READ (可重复读),repeatable read 是什么意思呢,意思就是上面的例子中,事务2,从始至终读取的age
都是1,不管事务1有没有提交。
有什么问题?
可重复读解决了不可重复读的问题,但是假如有下面的场景。
同时存在两个事务,事务1查询了user
表中age=25的数据,现在表里只有一条符合条件数据,自然查出了一条数据,假如现在事务2插入一条age=25的数据,之后事务1又查询了一下age=25的记录,此时发现竟然查出了两条记录,刚才明明还是一条,怎么现在出现了两条。即:本次查询出现了上次查询未出现的记录,像幻觉一样,这就是所谓幻读。
注意
REPEATABLE READ (可重复读) 通过 MVCC(多版本并发控制) 和 GAP LOCK(间隙锁) 的机制已经解决了幻读的问题。
SERIALIZABLE (串行化) 是4种事务隔离级别中隔离效果最好的,解决了脏读、可重复读、幻读的问题,但是性能最差,它将事务的执行变为顺序执行,与其他三个隔离级别相比,它就相当于单线程,后一个事务的执行必须等待前一个事务结束。
参考
https://baijiahao.baidu.com/s?id=1662096005584873447&wfr=spider&for=pc https://blog.csdn.net/hanpeiyu1995/article/details/90201894