首页 > 数据库 >你说熟悉MySQL事务,那来谈谈事务的实现原理吧!

你说熟悉MySQL事务,那来谈谈事务的实现原理吧!

时间:2023-03-19 18:35:56浏览次数:50  
标签:事务 隔离 数据 那来 undo MySQL redo log

事务的四大特性:原子性(Atomicity),一致性(Consistency),隔离型(Isolation)以及持久性(Durability)。

事务想要做到什么效果?无非是要做到可靠性以及并发处理:

  • 可靠性:数据库要保证当insert或update操作时抛异常或者数据库crash的时候需要保障数据的操作前后的一致,想要做到这个,我需要知道我修改之前和修改之后的状态,所以就有了undo log和redo log。
  • 发处理:也就是说当多个并发请求过来,并且其中有一个请求是对数据修改操作的时候会有影响,为了避免读到脏数据,所以需要对事务之间的读写进行隔离,至于隔离到啥程度得看业务系统的场景了,实现这个就得用MySQL 的隔离级别。

redo log

redo log叫做重做日志,是用来实现事务的持久性。该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。

当事务提交之后会把所有修改信息都会存到该日志中。

redo log 有什么作用?

mysql 为了提升性能不会把每次的修改都实时同步到磁盘,而是会先存到Boffer Pool(缓冲池)里头,把这个当作缓存来用。然后使用后台线程去做缓冲池和磁盘之间的同步。

那么问题来了,如果还没来的同步的时候宕机或断电了怎么办?这样会导致丢部分已提交事务的修改信息!

所以引入了redo log来记录已成功提交事务的修改信息,并且会把redo log持久化到磁盘,系统重启之后在读取redo log恢复最新数据。

redo log是用来恢复数据的 用于保障,已提交事务的持久化特性

undo log

undo log 叫做回滚日志,用于记录数据被修改前的信息。它正好跟前面所说的重做日志所记录的相反,重做日志记录数据被修改后的信息。undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。

每次写入数据或者修改数据之前都会把修改前的信息记录到 undo log。

undo log 有什么作用?

undo log 记录事务修改之前版本的数据信息,因此假如由于系统错误或者rollback操作而回滚的话可以根据undo log的信息来进行回滚到没被修改前的状态。

undo log是用来回滚数据的用于保障 未提交事务的原子性

mysql锁技术

当有多个请求来读取表中的数据时可以不采取任何操作,但是多个请求里有读请求,又有修改请求时必须有一种措施来进行并发控制。不然很有可能会造成不一致。

解决上述问题很简单,只需用两种锁的组合来对读写请求进行控制即可,这两种锁被称为:

共享锁(shared lock),又叫做"读锁"

读锁是可以共享的,或者说多个读请求可以共享一把锁读数据,不会造成阻塞。

排他锁(exclusive lock),又叫做"写锁"

写锁会排斥其他所有获取锁的请求,一直阻塞,直到写入完成释放锁

MVCC基础

MVCC (MultiVersion Concurrency Control) 叫做多版本并发控制。

InnoDB的 MVCC ,是通过在每行记录的后面保存两个隐藏的列来实现的。这两个列, 一个保存了行的创建时间,一个保存了行的过期时间,当然存储的并不是实际的时间值,而是系统版本号。

MVCC在mysql中的实现依赖的是undo log与read view:

  • undo log:undo log 中记录某行数据的多个版本的数据。
  • read view:用来判断当前版本数据的可见性

事务的实现

  • 事务的原子性是通过 undo log 来实现的
  • 事务的持久性性是通过 redo log 来实现的
  • 事务的隔离性是通过 (读写锁+MVCC)来实现的
  • 事务的一致性是通过原子性,持久性,隔离性来实现的

原子性,持久性,隔离性折腾半天的目的也是为了保障数据的一致性!

ACID只是个概念,事务最终目的是要保障数据的可靠性,一致性。

原子性的实现

一个事务中的所有操作要么全部成功提交,要么全部失败回滚,对于一个事务来说不可能只执行其中的部分操作,这就是事务的原子性。

以上概念相信大家伙儿都了解,那么数据库是怎么实现的呢?就是通过回滚操作。

所谓回滚操作就是当发生错误异常或者显式的执行rollback语句时,需要把数据还原到原先的模样,所以这时候就需要用到undo log来进行回滚。

  • 每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上
  • 所谓的回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insert,insert的逆向操作为delete,update的逆向为update等。

为什么先写日志后写数据库?

持久性的实现

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

MySQL的表数据是存放在磁盘上的,因此想要存取的时候都要经历磁盘IO,然而即使是使用SSD磁盘IO也是非常消耗性能的。

为此,为了提升性能InnoDB提供了缓冲池(Buffer Pool),Buffer Pool中包含了磁盘数据页的映射,可以当做缓存来使用:

  • 读数据:会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取在放入缓冲池;
  • 写数据:会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中;

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

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

于是 redo log就派上用场了。下面看下redo log是什么时候产生的。

事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。

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

  • redo log 的存储是顺序存储,而缓存同步是随机操作。
  • 缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。

隔离性实现

隔离性是事务ACID特性里最复杂的一个。在SQL标准里定义了四种隔离级别,每一种级别都规定一个事务中的修改,哪些是事务之间可见的,哪些是不可见的。

级别越低的隔离级别可以执行越高的并发,但同时实现复杂度以及开销也越大。

Mysql 隔离级别有以下四种(级别由低到高):

  • READ UNCOMMITED (未提交读)
  • READ COMMITED (提交读)
  • REPEATABLE READ (可重复读)
  • SERIALIZABLE (可重复读)

前面说过原子性,隔离性,持久性的目的都是为了要做到一致性,但隔离型跟其他两个有所区别,原子性和持久性是为了要实现数据的可性保障靠,比如要做到宕机后的恢复,以及错误后的回滚。

那么隔离性是要做到什么呢?隔离性是要管理多个并发读写请求的访问顺序。这种顺序包括串行或者是并行。

总之,从隔离性的实现可以看出这是一场数据的可靠性与性能之间的权衡。

  • 可靠性性高的,并发性能低(比如 Serializable)
  • 可靠性低的,并发性能高(比如 Read Uncommited)

READ UNCOMMITED (未提交读)

在READ UNCOMMITTED隔离级别下,事务中的修改即使还没提交,对其他事务是可见的。事务可以读取未提交的数据,造成脏读。

因为读不会加任何锁,所以写操作在读的过程中修改数据,所以会造成脏读。好处是可以提升并发处理性能,能做到读写并行。

  • 优点:读写并行,性能高
  • 缺点:造成脏读

READ COMMITED (提交读)

一个事务的修改在它提交之前的所有修改,对其他事务都是不可见的。其他事务能读到已提交的修改变化。在很多场景下这种逻辑是可以接受的。

InnoDB在 READ COMMITTED,使用排它锁,读取数据不加锁而是使用了MVCC机制。或者换句话说它采用了读写分离机制。

但是该级别会产生不可重读以及幻读问题。

什么是不可重读?

在一个事务内多次读取的结果不一样。

为什么会产生不可重复读?

这跟 READ COMMITTED 级别下的MVCC机制有关系,在该隔离级别下每次 select的时候新生成一个版本号,所以每次select的时候读的不是一个副本而是不同的副本。

在每次select之间有其他事务更新了我们读取的数据并提交了,那就出现了不可重复读。

REPEATABLE READ (可重复读,Mysql默认隔离级别)

在一个事务内的多次读取的结果是一样的。这种级别下可以避免脏读,不可重复读等查询问题。mysql 有两种机制可以达到这种隔离级别的效果,分别是采用读写锁以及MVCC。

采用读写锁实现

为什么能可重复读?只要没释放读锁,再次读的时候还是可以读到第一次读的数据。

  • 优点:实现起来简单
  • 缺点:无法做到读写并行

采用MVCC实现

为什么能可重复读?因为多次读取只生成一个版本,读到的自然是相同数据。

  • 优点:读写并行
  • 缺点:实现的复杂度高

但是在该隔离级别下仍会存在幻读的问题。

SERIALIZABLE (序列化)

该隔离级别理解起来最简单,实现也最简单。在隔离级别下除了不会造成数据不一致问题,没其他优点。

一致性的实现

数据库总是从一个一致性的状态转移到另一个一致性的状态。

实现事务采取了哪些技术以及思想?

  • 原子性:使用 undo log ,从而达到回滚
  • 持久性:使用 redo log,从而达到故障后恢复
  • 隔离性:使用锁以及MVCC,运用的优化思想有读写分离,读读并行,读写并行
  • 一致性:通过回滚,以及恢复,和在并发环境下的隔离做到一致性。

 

参考:

 

标签:事务,隔离,数据,那来,undo,MySQL,redo,log
From: https://www.cnblogs.com/xfeiyun/p/17233814.html

相关文章

  • 使用mysqldump对Mysql进行备份
    文档课题:使用mysqldump对Mysql进行备份.1、理论知识Mysqldump是用于转存储Mysql数据库的实用程序,它可以转储一个或多个MySQL数据库,对其进行备份或传输到远程服务器.其主要产......
  • 你说使用过ZooKeeper,那来说说他的基本原理吧
    ZooKeeper是一个开放源码的分布式应用程序协调服务,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。ZooKeeper设计目的最终一致性:client不论连接到哪个Serv......
  • MySQL如何正确查询字符串长度
    前言笔者最近有一个需求,需要将一段文字插入到备注字段remark前面。由于担心插入后超过字段长度的限制,所以需要统计线上数据,根据长度倒序查询remark最长的一批数据看看长......
  • 分布式事务解决方案总结 - 本地消息表
    1,什么是分布式事务?在传统架构中往往是一个单体架构,一个系统就对应一个war包,然后这个系统也只有一个数据库。即一个应用对应一个数据库,此时能满足传统的数据库事务,满足ACID......
  • 分布式事务
    一.XA型事务db-a:1,2,3------rm-adb-b:4,5,6------rm-b      TMdb-c:7,8,9------rm-c rm为资源管理器每个数据库都有TM为分布式事务管理器多......
  • 看看这份2023年MySQL终级面试题,提升你的内力,给你面试助力
    1、MySQL中有哪几种锁?(1)表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。(2)行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低......
  • 力扣586(MySQL)-订单最多的客户(简单)
    题目:编写一个SQL查询,为下了最多订单的客户查找customer_number。测试用例生成后,恰好有一个客户比任何其他客户下了更多的订单。查询结果格式如下所示。 进阶......
  • 力扣584(MySQL)-寻找用户推荐人(简单)
    题目:给定表 customer ,里面保存了所有客户信息和他们的推荐人。写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都 不是 2。对于上面的示例数据,结果为: ......
  • mysql的初体验——重装解决99%的问题
    这两天被java_web的作业搞得头皮发麻,主要原因就是因为jdbc连接数据库一直失败,甚至差点把电脑搞崩,删个注册表,结果用户变量也被删了,心态直接炸裂。有以下几个地方,引以为戒:1.......
  • mysql小知识点---interactive_timeout和wait_timeout区别
    interactive_timeout定义了对于交互式连接(比如使用cmd命令窗口或者在linux上连接msyql),服务器等待的最大时间,如果超过这个时间,服务端仍然没有受到数据,则会关闭连接;【我理解......