mysql的事务原理

1.什么是事务

        在mysql中的事务是由存储引擎实现的。支持事务的引擎主要为innodb。

        事务处理可以用来维护数据库的完整性,保证成批的sql语句要么全部执行,要么全部不执行。

2.事务的四大特性

        1.Atomicity(原子性):构成事务的所有操作必须是一个逻辑单元,要么全部成功,要么全部失败。

        2.Consistency(一致性):数据库在事务执行前后状态都必须是稳定的或者一致的,就是说事务开始和结束后,数据库的完整性不会被破坏。

        3.Isolation(隔离性):事务之间不会相互影响。由锁机制和MVCC机制来实现,四种隔离级别为:RU(读未提交)、RC(读已提交)、RR(可重复读)、SERIALIZABLE(串行化)。

        4.Durability(持久性):事务执行成功后必须全部写入磁盘,事务提交后,对数据的修改是永久性的,即使系统故障也不会丢失。

3.ACID实现原理

        总结来说,事务的隔离性由多版本控制机制和锁实现,而原子性、一致性、持久性通过Innodb的redo log、undo log和ForceLog at Commit机制来实现。

重做日志Redo Log

        如果要存储数据则先存储数据的日志,一旦内存崩了,则可以从日志找重做日志保证了数据的可靠性,Innodb采用了WAL(Write Ahead Log 预写日志)策略,即当事务提交时,先写重做日志,然后再挑选时间将脏页写入磁盘。如果发生宕机导致数据丢失,就通过重做日志进行数据恢复。

回滚日志Undo Log

        数据库崩溃重启后需要从redo log 中把未洛盘的脏页数据恢复出来,重新写入磁盘,保证用户的数据不丢失。当然,在崩溃恢复中还需要回滚没有提交的事务。由于回滚操作需要undo日志的支持,undo日志的完整性和可靠性需要redo日志来保证,所以崩溃恢复先做redo恢复数据,然后有必要的话做undo回滚(例如:redo log数据和binlog数据不一致,需要回滚redo log与binlog一致)。

        所以,在事务执行的过程中,除了记录redo log,还会记录一定量的undo log,undo log记录了数据在每个操作之间的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚。

Force Log at Commit机制

        它实现事务的持久性,即当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,然后事务的提交操作完成才算完成。为了确保每次日志都写入到重做日志文件,在每次将重做日志缓冲写入重做日志后,必须调用一次fsync操作(操作系统),将缓冲文件从文件系统缓存中正真写入磁盘。

        总结一下,就是redo log用于在崩溃时恢复数据,undo log用于对事物的影响进行撤销,也可以用于多版本控制。而Force Log at Commit机制保证事务提交后redo log日志都已经持久化。

4.原子性

        定义:原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。简单来说,要么全部成功,要么全部失败。

        实现原理:实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql。Innodb实现回滚,靠的是undo log,当事务对数据库进行修改时,Innodb会生成undo log;如果事务执行失败或者调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到之前的样子。

        逻辑日志和物理日志的区别:看记录日志的时候是针对一行记录,就是逻辑日志,如果是一个数据页,就是物理日志

        undo log属于逻辑日志,它记录的是sql执行相关的信息,当发生回滚时,Innodb会根据undo log的内容做与之前相反的工作:对于insert,回滚时会执行delete,对于delete,回滚时会执行insert,对于每个update,回滚时会执行一个相反的update把数据该回去。以下为例。

每条数据变更操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘。回滚过程如下。

5.持久性(Durability)

        定义:事务一旦提交,其所做的修改都会永久保存到数据库中,此时即使系统崩溃修改的数据也不会丢失。

        实现原理:依赖Redo log(WAL write ahead log)

        mysql的表数据是存放在磁盘上的,因此想要存取的时候都要经历磁盘io,然而即使是使用SSD磁盘IO也是非常消耗性能的。为此,为了提升性能,Innodb提供了缓冲池(Buffer Pool),Buffer Pool中包含了磁盘数据页的映射,可以当作缓存来使用:

  • 读数据:会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取再放入缓冲池;
  • 写数据:会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中(这一过程简称为脏刷);

        上面这种缓冲池的措施虽然在性能方面带来了质的飞跃,但是它也带来了新的问题,当mysql系统宕机,断电的时候可能会丢失数据!!!

        因为数据已经提交了,但此时是在缓冲池中,还没来得及磁盘持久化,所以我们急需一种机制需要存一下已提交事务的数据,为恢复数据使用。

        于是redo log就派上用场了。下面是redo log的生产过程。

        既然redo log也需要存储,也涉及磁盘io为啥还用它?

  • 刷脏是随机io,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序io。
  • 刷脏是以数据页为单位的,mysql默认页的大小是16kb,一个page上一个小修改都要整页写入,而redo log中只包含真正需要写入的部分,无效io大大减少。
6.隔离性(Isolation)

        定义:隔离性研究的是不同事物之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事物之间不能相互干扰。严格的隔离性,对应了事务隔离级别中的Serializable(可串行化),但实际应用中出于性能方面的考虑会用的很少。

        实现原理:隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们仅考虑最简单的读操作和写操作(暂时不考虑带锁读等特殊操作),那么隔离性的探讨,主要可以分为两个方面:

(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性

(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性

脏读、不可重复读、幻读

        并发情况下,读操作可能存在的三类问题:

  • 脏读:当前事务中读取了其他事务未提交的数据(脏数据),这种现象是脏读。
  • 不可重复读:在事务中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读和不可重复读区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
  • 幻读:在事务中按照某个条件先后查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗理解为:前者是数据变了,后者是数据的行数变了。

RR使用MVCC(mysql的mvcc原理_lunar@qq.com的博客-CSDN博客)解决了脏读、不可重复读,避免了幻读(还是有概率出现幻读,比如在两次快照读中间插入一次当前读就可能有概率重新生成readview导致出现幻读)

7.一致性

        一致性是事务追求的最终目标,前面提到的原子性、隔离性、持久性都是为了保证数据库的一致性。也就是说ACID四大特性中,C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值