第24章 一条记录的多幅面孔-事务的隔离级别和MVCC
事务隔离级别
如果不可以同时处理事务的话,那么只好让不同的事务进行排队了,这样对性能的影响很大
所以尽量想让服务器在访问同一数据的时候性能高一点,又想保持事务的隔离性,于是设置了事务的隔离级别
事务并发执行的问题
(1)脏写:一个事务修改了另一个未提交事务修改过的数据,那么就是发生了脏写
也就是之前两个事务交错进行的时候导致数据出现错误的情况
(2)脏读:也是同一个道理,一个事务读取到了一个即将被修改的数据,那么相当于读取到了一个根本不存在的数据
(3)不可重复读取:每次读取都是一个新的被修改后的值,那么这就是不可重复读取,字面意思很直接,就是之前的数据只能读取一次了
(4)幻读:读取到了之前读取中没有的记录,也就是无中生有的感觉在里面。幻读的原因在于这个事务读取的时候又另一个事务插入了新的记录在之前记录之间的间隙中的
SQL标准中四种隔离级别
脏写 > 脏读 >不可重复读取 >幻读
隔离级别越低,那么就越可能发生严重的问题
设置隔离级别实际上就是设置容错,在这个范围内允许出现一些并发事务的错误:

可以看到脏写没有,因为脏写太严重了,哪个级别中都不允许出现脏写
MySQL中支持四种隔离级别
不同的数据库厂商对于四种隔离级别的支持不一样,实际情况也不同
默认为REPEATABLE READ级别
设置事务的隔离级别
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;
level: {
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
}
其中GLOBAL和SESSION分别影响不同的范围的隔离级别
MVCC原理
版本链
每次更新记录都会将旧值存放到一个undo日志中,经过很多次更新以后,会产生很多旧的记录,这些记录通过roll-pointer属性连接形成一个链表,头节点就是最新的值。并且每个版本都会有对应的事务id
ReadView
对于READ UNCOMMITTED隔离级别的事务来说,直接读取最新版本的记录即可。但是对于SERIALIZABLE的级别事务来说,使用加锁的方式来访问记录
其余两个级别则是需要先判断一下版本链中哪个是当前事务可见的,不可以直接读取最新版以防止另一个事务已经修改了最新版的记录但是还没有提交
所以提出了ReadView的概念,包含的几个重要的属性可以用于判断某个版本是否可见,具体过程我就省略了哈哈哈💦
其实也就是通过它来屏蔽一些可能被正在修改的版本,尽量展示最正确而不是最新的版本给用户,它会判断每个版本直到找到符合要求的版本
READ COMMITTED---每次读取数据之前都会生成一个ReadView
通过对比不同版本的ReadView来确定版本是否可以展示给用户
REPEATABLE READ ------ 只会在第一次查询的时候生成ReadView
MVCC小结
MVCC就是多版本并发控制的意思,READ-COMMITTD、REPERATBLE READ两种隔离级别的事务在执行普通的查询操作时访问版本链的全过程,可以支持不同事务的并发执行从而提高了性能
只是两种级别的生成ReadView的时机不同,前者每次查询都生成一个,后者只会第一次的时候生成一个,后续每次查询都使用第一次产生的ReadView即可
个人思考:这个MVCC就是尽量让用户读到最正确的数据而不是最新的数据。通过ReadView来判断合适的版本提供给用户
总结
隔离级别:执行并发事务时允许的容错级别,容错越小则越严格,越不容易发生并发错误
MVCC:适用于中间两个级别的并发机制,通过ReadView在版本链中确定最适合事务的记录。这是一种并发的折中方案