我们在之前数据库的基础篇大致谈过一些事务的隔离级别的内容具体见添加链接描述
ACID四大特性分别是,atomicity原子性.consistency一致性,isolation隔离性以及durability持久性。
这里为什么需要隔离性,因为在实际工程当中,经常会出现一些问题,这些问题大致是:
脏读
不可重复读
幻读
为了解决上述问题,因此强调隔离性。
拿上述两个事务来举例,头两种相信大家都清楚v值应该是多少。我们来解释一下:
实现方面,数据库会创建一个视图,访问数值以视图逻辑为准。
即
读未提交级别,直接返回最新值,没有视图概念。
读已提交级别,视图在SQL语句开始执行时创建
可重复度级别,视图在事务启动之前创建,整个事务运行期间都保持这个视图。
可串行化级别,直接用加锁方式避免并行访问。
展开说明一下可重复读是如何实现的。
MySQL实际上在每条记录被更新的同时都会记录一条回滚操作 ,通过回滚操作,可以得到任意状态的值。回滚日志一直被保留,直到没有事务需要这些回滚事务为止。
我们看到一个值从1被改到4.但是不同时刻启动事务会得到不同视图,不同值
视图A,只看到了值变成了1。后面以此类推B看见了是2,C看见了现在的值是4.
所以要尽可能避免使用长事务
长事务意味着数据库中,此时会有很老的视图,即牵扯到很大量的回滚日志保留下来,大量空间被占用。除此之外,长事务还占用锁资源。
这主要是受到Oracle数据库设定的影响。
什么场景需要可重复读呢?即希望在事务进行中,即使数据发生变化,也不影响我的结果。
比如你有上个月的账本和这个月的,你在做校对的时候不会关心现在银行有没有人存取钱,因为需要校对的内容已经记在这个月的账本上了,此时此刻银行事务的变化,不会影响你校对。
MVCC,全称 Multi-Version Concurrency Control,多版本并发控制。
最大的作用是帮助我们实现可重复读的同时,避免了读的时候加锁,只有在写的时候才进行加锁,从而提高了系统的性能。核心是通过引入版本或者视图来实现的。
几个前提概念:
在可重复读的隔离性下,MVCC 是如何工作的呢?
核心的可见性保证来自于读视图的建立,本质就是每个事务开始前,会记录下当前仍在活跃也就是开始但未提交的所有事务,保存在一个数组中,我们称为视图数组,然后会根据这个数组,基于一定的规则判断应该读取每个数据的哪个快照。
记录视图数组中最小的事务ID——称为低水位。最大的事务ID+1——称为高水位。
规则:
这两个 ID 其实就可以从当前执行的事务的视角,将所有的事务分为三个部分,
记低水位为low_id,高水位为high_id,活跃事务数组为trx_list。
可见的事务IDtrix_id应该满足:trix_id
即,可见事务要么比低水位更低,要么不在活跃事务却比高水位低。
有了这个视图的声明,系统后续发生的更新一定属于不可见的状态,所以是可重复读的。
读视图的规则其实就是根据可见性的约束,在查询数据的时候从版本链从最新往前遍历,直至找到第一个可见的版本返回。
例子:
在事务A之前,id=1的隐藏列事务trix_id是1.
那么事务A启动,由于B最先,A次之,然后是C。所以A申请到trix_id=3.在A的视图数组里,他启动的时候,只有B是活跃的,所以trix_list=[trix_id=2]。
在T4时间
MVCC 基于 undo_log 和版本链的乐观控制并发的方式,本质上就是要通过多版本的快照读,在实现隔离性的同时,帮助我们避免读的时候加锁的操作。
对于更新数据的操作,都是先读后写,读只能读当前值。
更新完了看自己的trix_id是不是最新的,如果是就可以直接用。
核心是一致性读,事务更新数据只能用当前读,如果当前记录被别的行锁占用,就要等待。
读已提交和可重复度的主要区别: