MYSQL独孤九剑(三)事务隔离MVCC

    淦,美剧硅谷真好看,看的我都不想更了,没有荒腔走板,不多bb,本周讲事务的隔离性。提到事务大家肯定都不陌生,最经典的例子就是转账,你要给朋友转100块钱,而此时你的银行卡只有100块钱。那么在程序中就会有一序列操作,查询你的余额判断是否大于等于100块、减去你余额中100加到朋友的账户上、更新双方余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这100块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就能白嫖了吗,这时就要用到“事务”这个概念了。简单的说,事务就是保证一组数据库操作要么全都成功,要么全都失败。

​事务的隔离机制

    面试高频知识点事务的四大特性,ACID(原子性、一致性、隔离性、持久性),这次就说一下Isolation,事务的隔离性。当数据库有多个事务执行的时候就可能出现各种问题,脏读、幻读、不可重复读等,简单说一下。

脏读:在一个事务中读到了其他事务保存但未提交的数据。

幻读:一个事务在进行中读到了其他事务对旧数据修改的结果(比如开一个事务  修改某条数据 先查后改 执行了修改动作 的时候发现这条数据已经被别的事务删除了,前后多次读取,数据内容不一致)

不可重复读:幻读与不可重复读类似,不可重复读读到了别人update/delete的数据,幻读读到了别人insert的数据。一个事务在读取了其他事务新增的数据,仿佛出现了幻想(前后多次读取,数据数量不一致)

    为了解决这些问题就有了“隔离级别”,但鱼与熊掌不可得兼,你隔离的越严实,性能越拉跨。SQL标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。

读已提交是指,一个事务提交之后,它做的变更才会被其他事务看到。

可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。

串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

 

MYSQL独孤九剑(三)事务隔离MVCC_第1张图片

借助这个经典图理解一下这几个隔离级别。

若隔离级别是“读未提交”, 则V1的值就是2。这时候事务B虽然还没有提交,但是结果已经被A看到了。因此,V2、V3也都是2。

若隔离级别是“读提交”,则V1是1,V2的值是2。事务B的更新在提交后才能被A看到。所以, V3的值也是2。

若隔离级别是“可重复读”,则V1、V2是1,V3是2。之所以V2还是1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。

若隔离级别是“串行化”,则在事务B执行“将1改成2”的时候,会被锁住。直到事务A提交后,事务B才可以继续执行。所以从A的角度看, V1、V2值是1,V3的值是2。

隔离机制的实现

   在可重复度的隔离机制下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录。这里说一下这个回滚日志就是undolog,是不是很熟悉,跟上一篇的redolog很像,只不过他俩一个是往前滚,一个是往后滚。。。系统会判断当没有事务需要用到这些回滚日志时,回滚日志会被删除。

MYSQL独孤九剑(三)事务隔离MVCC_第2张图片

    每行数据也都是有多个版本的,每次事务更新数据的时候,都会生成一个新的数据版本,并且把transaction id赋值给这个数据版本的事务ID,记为row trx_id。同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。也就是说,数据表中的一行记录,其实可能有多个版本,每个版本有自己的row trx_id。然后你就会发现当前值是4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的read-view。如图中看到的,在视图A、B、C里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。 

    也就是说在查询时要符合以下两个条件的记录才能被事务查询出来:

    1.删除版本号未指定或者大于当前事务版本号,即查询事务开启后确保读取的行未被删除。(即上述事务id为2的事务查询时,依然能读取到事务id为3所删除的数据行)

    2.创建版本号 小于或者等于 当前事务版本号 ,就是说记录创建是在当前事务中(等于的情况)或者在当前事务启动之前的其他事物进行的insert。

    这样看起来很像乐观锁的实现方式,通过版本号来保证数据的一致~

 

你可能感兴趣的:(MYSQL独孤九剑(三)事务隔离MVCC)