数据库——MySQL之ACID及其实现

1. A:Atomicity,原子性

  • 原子性

一个事务必须被视为一个不可分割的最小单位,要不全部提交成功,要么全部失败回滚

  • 实现:undo log

undo log称之为回滚日志,每条数据的变化(insert/update/delete)都会产生一条记录,并且日志持久化到磁盘,undo log用来记录数据修改前的信息,比如说要插入一条记录,那么undo log就会记录一条删除该信息的语句,这样你需要回滚的时候那么undo log就会执行删除你之前插入的那条记录,达到没有修改前的状态,更新一个记录也会生成一条sql记录你更新前的字段状态,从而实现了原子性。

2. C:Consistency,一致性

  • 一致性

数据库总是从一个一致性的状态转换到另外一个一致性状态,不会部分数据状态改变而另一部分数据状态没有改变

数据一致性是最基本的属性,其它的三个属性都为了保证一致性而存在的。

3. I:Isolation,隔离性

  • 隔离性

通常来说,一个事务所做的修改在最终提交之前,对其他事务是不可见的

4. D:Durability,持久性

  • 持久性

一旦事务提交,则其所做的修改会被永久保存到数据库中

  • 实现:redo log

mysql为了提升性能不会把每次的修改都实时同步到磁盘中,而是先存到缓存中,然后再使用线程去做缓冲池和磁盘中的同步。这样必然会存在问题,假如电脑突然停电,那么没有持久化到磁盘的信息必然会丢失,那么持久性如何实现?答:redolog

  • 关于记录日志

redo log叫重做日志,记录的是数据修改之后的值,不管事务是否提交都会记录下来。在实例和介质失败(media failure)时,redo log文件就能派上用场,如数据库掉电,InnoDB存储引擎会使用redo log恢复到掉电前的时刻,以此来保证数据的完整性。在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中

  • 关于持久化日志

在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,这里涉及到WAL即Write Ahead logging技术,他的关键点是先写日志,再写磁盘。

  • 结果

有了redo log日志,那么在数据库进行异常重启的时候,可以根据redo log日志进行恢复,也就达到了crash-safe。

  • 结构

redo log日志的大小是固定的,即记录满了以后就从头循环写
在这里插入图片描述

  • 扩展:binlog

1、binlog是server层实现的,意味着所有引擎都可以使用binlog日志
2、binlog通过追加的方式写入的,可通过配置参数max_binlog_size设置每个binlog文件的大小,当文件大小大于给定值后,日志会发生滚动,之后的日志记录到新的文件上。
3、binlog有两种记录模式,statement格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。

作者:会玩code 链接:https://www.jianshu.com/p/4bcfffb27ed5 来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 扩展:两阶段提交

在这里插入图片描述

  • 为什么需要两阶段提交:

binlog是MySQL中Server层的日志,redo log是InnoDB存储引擎特有的。

如果先写redo log然后写binlog:如果redo log写完后,写binlog的时候,MySQL进程异常重启。但是我们redo
log写入了这条更新,所以重启后这条数据依然会被修改。但是因为binlog还没有写完就崩溃了,当我们需要用binlog来恢复临时库的时候就发现少了一次更新,这时候就会发生不一致。

如果先写binlog然后写redo log:如果binlog写完之后,redo
log还没有写完就异常重启。那么InnoDB引擎就会判断事物无效,回滚这次操作。但是binlog里面却记录了这次操作。当我们使用binlog来恢复的时候就又多了一个事务,这时候又会数据不一致。

  • 两阶段出现故障:

在这里插入图片描述

时刻A发生故障:这时候发生故障的话,redo log处于prepare阶段,此时redo
log还没有提交所以崩溃恢复的时候这个事务就会回滚本次提交。因为binlog还没有写,所以恢复数据的时候也不会执行此次事务

时刻B发生了故障:如果时刻B说明redo
log处于prepare阶段,并且binlog已经写完了。但是执行器调用存储引擎提交事务时候,redo
log还没来记得修改为commit的时候发生崩溃。那么此时就需要分情况。

重启过后InnoDB引擎发现redo
log是prepare阶段,那么就会根据自己的XID去寻找对应的binlog(XID是他们共同的数据字段)。如果binlog是完整的,这时候极有可能binlog已经被备库同步了,那么此时直接提交事务。如果binlog不是完整的,那么此时回滚事务。

看到这里不知道你会不会有一个疑惑。处于prepare状态的redo log和完整的binlog就可以崩溃恢复了,为什么还要再设计redo
log的commit阶段?

我们继续用反证法,如果没有commit阶段的话。当我们写入redo
log后事务提交,然后写binlog的时候写入失败发生了崩溃。但是事务已经提交了,就不能回滚了。如果允许回滚的话,提交事务和写binlog这之间其他事务也对这条记录进行修改,回滚就会覆盖其他事务的更新。

———————————————— 版权声明:本文为CSDN博主「活在梦里丶」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_25448409/article/details/105376450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值