MySql 笔记(四)Mysql事务的提交及底层实现原理
在写这篇博客的时候,也有在网上翻阅大量的资料,CSDN、知乎等平台,花了一个多星期去理解和掌握这些知识,在网上确实也有些文章写的也有很多不一样的地方,很多文章都是有错误的,我们需要对这些文章有自己的判别,还是要结合自己的看法来。然后包括自己要组织语言写起来,也是要重新去翻阅很多其他的资料。下面算是一些总结,加上自己的一些理解吧。
写在前面
在网上有一个总结的很好的一句话,在这里记下来:
- 事务的原子性是通过 undo log 来实现的。
- 事务的持久性性是通过 redo log 来实现的。
- 事务的隔离性是通过 (读写锁+MVCC)来实现的。
- 事务的一致性是通过原子性,持久性,隔离性来实现的。
事务的提交
说一下二阶段提交
表示redo log分为prepare阶段和commit阶段这样的两个阶段提交。它的流程是这样的:
- redo log在prepare后会写入磁盘,保证日志不丢失
- binlog写入磁盘
- 在commit阶段又会给redo log写入commit的状态。且提交了就会使数据具有可见性。
为什么需要二阶段提交?
用反证法来证明,如果没有二阶段提交:
- 先写redolog为commit状态再写binlog,如果redolog写入磁盘成功后直接挂了,然后重启mysql后通过redolog进行了数据恢复,但是binlog中缺失了该记录日志,那么从库通过binlog日志去复制的时候就会比这个库要少一个数据修改,导致主从不一致。
- 先写binlog再写redolog为commit状态,如果binlog写入磁盘成功后直接挂了,那么,mysql重启后不能通过redolog来恢复数据,但是从库却能通过binlog多一个数据修改出来,导致主从不一致。
数据恢复阶段会使用到binlog和redo log:
- 在mysql故障重启之后,是怎么进行数据恢复的呢?在它的日志系统中,binlog和redolog中有一个公共字段XID是对应起来的,首先要看redo log中有没有prepare,有prepare就会直接去binlog中找,而binlog中有对应的日志则继续提交,没有数据则回滚。
binlog和redolog的组提交:
如果数据的并发量较高的话,即使是顺序的写入磁盘,频繁的IO操作会使得服务器的性能大幅下降。为了提高磁盘的写入效率,可以把多个日志攒到一起再写入磁盘,这就是组提交。
而由于使用了binlog和redo log,所以这两个日志是都要使用组提交的,不然没使用组提交的哪一个一样会成为瓶颈所在。
这个组提交和之前的双一设置我感觉应该是不冲突的,每次写binlog或者redo log的时候都会等待多个事务一起过来成组的写入,依然是符合双一设置的,不过就是事务还会有一个等待的过程。
它主要有三个阶段:
1.flush阶段
2.sync阶段
3.commit阶段
它的每个阶段都分别有一个队列和一把锁,他们的流程如下:
flush阶段:
- 不断的有事务加入到flush队列