当前位置:   article > 正文

2 事务

2 事务

来源:

《MySQL实战45讲》

MVCC:https://mp.weixin.qq.com/s/bM_g6Z0K93DNFycvfJIbwQ(MVCC算法图)

MySQ Binlog日志格式:https://www.cnblogs.com/baizhanshi/p/10512399.html

Force Log at Commit:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html
在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。

总结来说:事务的隔离性由多版本控制机制和锁实现,原子性、一致性和持久性由InnoDB的redolog(持久性)、undolog(原子性)和Force Log at Commit机制(持久性)实现,原子性和持久性则保证了一致性

1 事务隔离性与隔离级别

在MySQL中,事务支持是在引擎层实现的,此处讲解InnoDB的事务的隔离性

读未提交:⼀个事务还未提交,但它所做的变更可以被其他事务看到
读提交:⼀个事务提交之后,它所做的变更才可以被别的事务看到;
所以如果此事务修改了值再提交,则其他事务在此事务提交前后查询此值时会结果不一致
可重复读:⼀个事务执行过程中看到的数据是⼀致的,当前事务未提交时,其他事务修改的值不会影响自己
串行化:对应⼀个记录会加读写锁,出现冲突的时候,后访问的事务必须等前⼀个事务执行完成才能继续执行

在实现上,数据库会创建⼀个视图,访问的时候以视图的逻辑结果为准,这个视图是InnoDB在实现MVCC时用到的一致性读视图,即read-view,作用是在事务执行期间定义“我能看到什么数据“(类似内存屏障?):

在“读未提交”隔离级别下,直接返回记录上的最新值,没有视图概念:
因此如果读取到的值被其他事务做了修改,则如下图的当前值立马就被更改了,读取到的值也就跟原先的不一样了;

在“读提交”隔离级别下,这个视图是在每个SQL语句开始执行的时候创建的:
因此如果读取到的值被其他事务做了修改,但是还未提交,没有更新到表里,SQL语句的结果还是不变;
但是如果修改了值后提交了,则意味着表进行了更新,所以结果也就变了

在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图,此视图可以认为是静态的,不受其他事务更新的影响,使用的技术是”快照“:
因此就算提交了,也不影响这个静态的视图,也就不存在两次查询结果不一致的情况了;
不过当前事务可能在查询时只出现了三条数据,但是当其他事务插入数据时,当前事务再次查询,就出现了四条数据,此为幻读,原因见下文解析

“串行化”隔离级别下直接用加锁的方式来避免并行访问:
直接加锁,产生冲突时,其他后访问的事务被锁住,等当前事务提交了之后,其他后访问的事务才能继续执行;
即事务读数据则加表级共享锁,事务写数据则加表级排他锁

解析一下可重复读(在2中会进一步解析):

在MySQL中,实际上每条记录在更新的时候都会同时记录⼀条回滚操作。
记录上的最新值,通过回滚操作,都可以得到前⼀个状态的值。

假设⼀个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录:
在这里插入图片描述
当前值是4,而在查询这条记录的时候,不同时刻启动的事务会有不同的read-view,即同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)

如对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

可以看到,这种方式只是防止了更新,并没有防止插入、删除操作,这也是幻读的原因

当系统里没有比这个回滚日志更早的read-view的时候,就可以删除这些回滚日志了;
可以看到,这种实现方式如果使用了长事务,会导致大量的回滚记录大量占用存储空间;
还占用锁资源,可能拖垮整个库

2 事务的隔离问题

本文涉及的表如下:

CREATE TABLE `t` (
`id` int(11) NO
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/239609
推荐阅读
相关标签
  

闽ICP备14008679号