事务的四种隔离级别是如何实现的?
·对于"读未提交"隔离级别的事务来说,因为可以读到未提交事务修改的数据,所以直接读取最新的数据就好了。
·对于"读提交"和"可重复读"隔离级别的事务来说,它们是通过ReadView来实现的。它们的区别在于创建ReadView的时机不同。大家可以把ReadView理解成一个数据快照,就像相机拍照那样定格某一时刻的风景。
→"读提交"隔离级别是在每个select前都会生成一个新的ReadView。
→而"可重复读"隔离级别是启动事务时生成一个ReadView,然后整个事务期间都在用这个ReadView。
→读提交隔离级别是在每次读取数据时都会生成一个新的ReadView,也意味着事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致。因为可能这期间另外一个事务修改了该记录并提交了事务。所以可重复读隔离级别下,一个事务中执行两次sql语句只会生成一次readview。
·对于"串行化"隔离级别的事务来说,通过加读写锁的方式来避免并行访问。但是可重复读隔离级别下,MySOLInnoDB引擎的默认隔离级别虽然是"可重复读",但是它很大程度上避免幻读现象(并不是完全解决了)。
解决的方案有两种:
→针对快照读(普通select语句),是通过MVCC方式解决了幻读AND。因为可重复读隔离级别下,事务执行过程中看到的数据一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据是查询不出来这条数据的,所以就很好了避免幻读问题。
→针对当前读/select..forupdate等语句),是通过next-keylock(记录锁+间隙锁)方式解决了幻读。因为当执行selectforupdate语句的时候会加上next-keylock。如果有其他事务在next-key,lock锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
可重复读为什么完全不能解决幻读?是在快照读的情况下出现的,比如事务A对事务B插入的数据进行了更新,然后这条数据就被事务A认为是自己的数据。在可重复读隔离级别下,事务A第一次执行普通的select语句时生成了一个ReadView,之后事务B向表中新插入了一条id=5的记录并提交。
接着事务A对id=5这条记录进行了更新操作,在这个时刻这条新记录的trx隐藏列的值就变成了事务A的事务ide1o7,之后事务A再使用普通select语句去查询这条记录时就可以看到这条记录,于是就发生了幻读。
因为这种特殊现象的存在,所以我们认为MySQLInnodb中的MVCC并不能完全避免幻读现象。





