mysq 事务实现的原理

182 阅读6分钟

mysql 事务实现的原理

可靠性

数据库要保证当insert或update操作时抛异常或者数据库crash的时候需要保障数据的操作前后的一致,想要做到这个,我需要知道我修改之前和修改之后的状态,所以就有了undo log和redo log

并发处理

也就是说当多个并发请求过来,并且其中有一个请求是对数据修改操作的时候会有影响,为了避免读到脏数据,所以需要对事务之间的读写进行隔离,至于隔离到啥程度得看业务系统的场景了,实现这个就得用MySQL 的隔离级别。

redo log 与 undo log

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 分为insert_undo_log和update_undo_log
  • insert_undo_log:事务对insert新记录时产生的undolog,只在事务回滚时需要, 并且在事务提交后就可以立即丢弃。
  • update undo log : 事务对记录进行delete和update操作时产生的undo log, 不仅在事务回滚时需要, 一致性读也需要,所以不能随便删除,只有当数据库所使用的快照中不涉及该日志记录,对应的回滚日志才会被purge线程删除。
  • undo log是用来回滚数据的用于保障 未提交事务的原子性

mysql 锁

共享锁(shared lock)

  • 又叫做"读锁",读锁是可以共享的,或者说多个读请求可以共享一把锁读数据,不会造成阻塞。可并行

\color{green}排他锁(exclusive lock)

  • 又叫做"写锁",写锁会排斥其他所有获取锁的请求,一直阻塞,直到写入完成释放锁。不可并行
通过读写锁,可以做到读读可以并行,但是不能做到写读,写写并行。事务的隔离性就是根据读写锁来实现的

MVCC基础

InnoDB的 MVCC(MultiVersion Concurrency Control) 叫做多版本并发控制,是通过在每行记录的后面保存两个隐藏的列来实现的。这两个列, 一个保存了行的创建时间,一个保存了行的过期时间, 当然存储的并不是实际的时间值,而是系统版本号。
  • MVCC在mysql中的实现依赖的是undo log与read view
    • undo log :undo log 中记录某行数据的多个版本的数据。

    • read view :用来判断当前版本数据的可见性

事务的实现

  • 事务的原子性是通过 undo log 来实现的

  • 事务的持久性性是通过 redo log 来实现的

  • 事务的隔离性是通过 (读写锁+MVCC)来实现的

  • 而事务的终极大 boss 一致性是通过原子性,持久性,隔离性来实现的!!!

undo log的生成

  • 每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上

  • 所谓的回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insert,insert的逆向操作为delete,update的逆向为update等。

根据undo log进行回滚

为了做到同时成功或者失败,当系统发生错误或者执行rollback操作时需要根据undo log 进行回滚

回滚操作就是要还原到原来的状态,undo log记录了数据被修改前的信息以及新增和被删除的数据信息,根据undo log生成回滚语句,比如

  • 如果在回滚日志里有新增数据记录,则生成删除该条的语句

  • 如果在回滚日志里有删除数据记录,则生成生成该条的语句

  • 如果在回滚日志里有修改数据记录,则生成修改到原先数据的语句

持久性的实现

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

MySQL的数据存储机制,MySQL的表数据是存放在磁盘上的,因此想要存取的时候都要经历磁盘IO,然而即使是使用SSD磁盘IO也是非常消耗性能的。
为此,为了提升性能InnoDB提供了缓冲池(Buffer Pool),Buffer Pool中包含了磁盘数据页的映射,可以当做缓存来使用:
读数据:会首先从缓冲池中读取,如果缓冲池中没有,则从磁盘读取在放入缓冲池;
写数据:会首先写入缓冲池,缓冲池中的数据会定期同步到磁盘中;

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

  • redo log 的存储是顺序存储,而缓存同步是随机操作。

  • 缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。

参考