mysql日志系统和事务的理解

版权声明:转载请注明出处 https://blog.csdn.net/h2604396739/article/details/84847455

本文主要讲的是日志系统,以及日志系统和事务的关系。

事务的特性(acid)

Atomic:原子性,指的是事务是一个不可再分割的单位,要么全部成功,要么全部失败

Consistency:一致性,在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

Isolation:隔离性,事务之间的操作互不影响,通过锁实现

Durability:持久性,事务一旦提交,其结果就是稳定的,即使发生了宕机等,也可以将数据恢复。

数据完整性约束指的是为了防止不符合规范的数据进入数据库,在用户对数据进行插入、修改、删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确、有效、相容。

 

实现方式:

隔离性:通过锁来实现,此时分为不加锁,乐观锁,悲观锁,行锁,表锁

持久性:通过redo log 来实现

扫描二维码关注公众号,回复: 4473713 查看本文章

原子性和一致性:通过undo来实现

 

WALWrite-Ahead Logging)是一种实现事务日志的标准方法,具体而言就是:

1、修改记录前,一定要先写日志;

2、事务提交过程中,一定要保证日志先落盘,才能算事务提交完成。

通过WAL方式,在保证事务特性的情况下,可以提高数据库的性能。

 

简单来说,redo log 记录事务修改后的数据, undo log 记录事务前的原始数据。redo恢复提交事务修改的页操作,而undo回滚行记录到某个特定的版本。Binlog用于记录整个对库的修改过程,包括所有执行的sql,用于数据库的主从数据同步

 

Undo log:发生于事务开始之前,在buffer中根据当前的数据版本生成逻辑格式的日志,能够保存事务发生之前的数据的一个版本,可以用于回滚,undo操作也使用了缓存,在事务提交的时候会同时将数据和undo日志更新到磁盘,这步操作就是和redo的主要区别,并且该操作对磁盘IO的消耗非常大,所以undo操作保证了事务的原子性,事务一旦提交数据也被持久化了。

 

Redo log:先在buffer中根据物理数据页面的修改生成物理格式的日志,然后在事务提交之前redo log会持久化,即比undolog和数据先持久化,数据的持久化会在后面的线程刷新操作过程中被更新,redo操作事务提交后只有redo和binlog被持久化,数据暂时未被持久化,在数据持久化时如果发生了故障,尚有脏页未写入磁盘,在重启mysql服务的时候,可根据redo log进行重做,从而达到事务的持久性这一特性。实际上 redo log 的写入拆成了两个步骤:prepare commit,这就是"两阶段提交"。在preparecommit之间会记录binLog日志,commit时会同时持久化binlogredoLog

Bin log:发生于redologpreparecommit之间,用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。同时用于数据库的基于时间点的还原。

 

事务提交过程中,主要做了4件事情,

1、刷redo日志,前面我们说到,mysql实现事务一致性和持久性的机制。通过redo日志落盘操作,保证了即使修改的数据页没有及时更新到磁盘,只要日志是完成了,就能保证数据库的完整性和一致性;

2、清理undo段信息,对于innodb存储引擎的更新操作来说,undo段需要purge,这里的purge主要职能是,真正删除物理记录。在执行deleteupdate操作时,实际旧记录没有真正删除,只是在记录上打了一个标记,而是在事务提交后,purge线程真正删除,释放物理页空间。因此,提交过程中会将undo信息加入purge列表,供purge线程处理。

3、释放锁资源,mysql通过锁互斥机制保证不同事务不同时操作一条记录,事务执行后才会真正释放所有锁资源,并唤醒等待其锁资源的其他事务;

4、清理保存点列表,每个语句实际都会有一个savepoint(保存点),保存点作用是为了可以回滚到事务的任何一个语句执行前的状态,由于事务都已经提交了,所以保存点列表可以被清理了。

 

 Undo + Redo事务的简化过程

  假设有AB两个数据,值分别为1,2,开始一个事务,事务的操作内容为:把1修改为32修改为4,那么实际的记录如下(简化):

事务开始

记录A=1,undo log buffer

修改A=3

记录A=3redo log buffer

Binlog记录 update A=3语句--binglog还没有持久化?

记录B=2undo log buffer----此时crash,恢复的话A=1,事务未提交

修改B=4

记录B=4redo log buffer----redoLog prepare阶段,此时crash,恢复的话B=2,事务未提交

Binlog记录 update B=4语句,binlog尚未持久化----此时宕机,恢复的话B=2

Redo logbinLog持久化--- commit阶段,此时crash,恢复的话B=4A=3

事务提交,同时 undoLogA=3B=4的值持久化

 

什么时候事务算提交完毕?

bingLogredoLog commit持久化后,事务提交完毕,在此之前crash事务没有提交,crash的话事务不生效,未提交,在此之后事务提交完毕,事务提交成功,可恢复。

 

Redologbinglog的区别:

binlog的作用之一是还原数据库的,这与redo log很类似,很多人混淆过,但是两者有本质的不同

1,作用不同:redo log是保证事务的持久性的,是事务层面的,binlog作为还原的功能,是数据库层面的(当然也可以精确到事务层面的),虽然都有还原的意思,但是其保护数据的层次是不一样的。

2,内容不同:redo log是物理日志,是数据页面的修改之后的物理记录,binlog是逻辑日志,可以简单认为记录的就是sql语句

3redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。追加写是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

4,恢复数据时候的效率,基于物理日志的redo log恢复数据的效率要高于语句逻辑日志的binlog

5redo log InnoDB 引擎特有的;binlog MySQL Server 层实现的,所有引擎都可以使用。

 

数据恢复:

当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

  • 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
  • 然后,从备份的时间点开始,将备份的 binlog 依次取出来,重放到中午误删表之前的那个时刻。但是到此步会丢失12点到2点之间的数据操作,所以下面还有一部。
  • 然后干掉那个误删操作的sql后,再从误删表时刻开始执行12点到当前时间的binglog

这样你的临时库就跟误删之前的线上库一样了,然后你可以把表数据从临时库取出来,按需要恢复到线上库去

 

关于redoLog分阶段提交(即redo preparebinglogredo commit)原因

仍然用前面的 update 语句来做例子。假设当前 ID=2 的行,字段 c 的值是 0,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?

  1. 先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1
    但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
    然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
  2. 先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了 c 0 改成 1”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。

可以看到,如果不使用两阶段提交,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

但是即使使用了分阶段提交,也有可能是binlog写完发生crashredo没有commit的场景,此时恢复不是和上面的场景2一样吗???

主要原因是redocommit阶段实际是redobinlog持久化,所以恢复的话一定是redobinglog都持久化或者都没有持久化,保证了一致性。

要 binlog 没写成功,整个事务是需要回滚的,而 binlog 和redoLog写成功后即使 MySQL Crash 了都可以恢复事务并完成提交。要做到这点,就需要把 binlog和redoLog的commit 和事务关联起来,而只有保证了 binlog与redoLog 和事务数据的一致性,才能保证主从数据的一致性。

猜你喜欢

转载自blog.csdn.net/h2604396739/article/details/84847455