mysql学习笔记二

事务

事务及其特性

事务是指作为单个逻辑工作单元执行的一系列操作,这些操作要么全做,要么全不做,是一个不可分割的工作单元。

事务的四个基本特性

一致性

事务开始之前和事务结束之后,数据库的完整性限制未被破坏。
约束一致性:数据库中创建表结构时所指定的外键、Check、唯一索引等约束。在 MySQL 中不支持 Check ,只支持另外两种。
数据一致性:是一个综合性的规定,是由原子性、持久性、隔离性共同保证的结果。

一致性背后的技术

一致性可以归纳为数据的完整性。数据的完整性是通过其他三个特性来保证的,包括原子性、隔离性、持久性,而这三个特性,又是通过 Redo/Undo 来保证的,正所谓:合久必分,分久必合,三足鼎力,三分归晋,数据库也是,为了保证数据的完整性,提出来三个特性,这三个特性又是由同一个技术来实现的。
在这里插入图片描述

原子性

事务的所有操作,要么全部完成,要么全部不完成,不会结束在某个中间环节。
即要么改了,要么没改,用户感受不到一个正在改的状态
MySQL 是通过 WAL(Write Ahead Log)技术来实现这种效果,如果事务提交了,那改了的数据就生效了,如果此时 Buffer Pool 的脏页没有刷盘,就需要使用 Redo 日志恢复出来的数据。而如果事务没有提交,且 Buffer Pool 的脏页被刷盘了,那这个本不应该存在的数据的消失就需要通过 Undo 来实现,而Undo 又是通过 Redo 来保证的,所以最终原子性的保证还是靠 Redo 的 WAL 机制实现的。

原子性背后的技术

每一个写事务,都会修改 Buffer Pool,从而产生相应的 Redo 日志,这些日志信息会被记录到 ib_logfiles 文件中。因为 Redo 日志是遵循 Write Ahead Log 的方式写的,所以事务是顺序被记录的。
在 MySQL 中,任何 Buffer Pool 中的页被刷到磁盘之前,都会先写入到日志文件中,这样做有两方面的保证。
如果 Buffer Pool 中的这个页没有刷成功,此时数据库挂了,那在数据库再次启动之后,可以通过 Redo 日志将其恢复出来,以保证脏页写下去的数据不会丢失,所以必须要保证 Redo 先写。
因为 Buffer Pool 的空间是有限的,要载入新页时,需要从 LRU (最近最少使用)链表中淘汰一些页,而这些页必须要刷盘之后,才可以重新使用,那这时的刷盘,就需要保证对应的 LSN (Log sequence number,日志序列号)的日志也要提前写到 ib_logfiles 中,如果没有写的话,恰巧这个事务又没有提交,数据库挂了,在数据库启动之后,这个事务就没法回滚了。所以如果不写日志的话,这些数据对应的回滚日志可能就不存在,导致未提交的事务回滚不了,从而不能保证原子性,所以原子性就是通过 WAL 来保证的。

持久性

事务完成之后,事务所做的修改进行持久化保存,不会丢失。
持久性,就是指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,接下来的操作或故障不应该对其有任何影响,通过原子性,即便是遇到宕机,也可以从逻辑上将数据找回来后再次写入物理存储空间,这样就从逻辑和物理两个方面保证了数据不会丢失,即保证了数据库的持久性。

持久性背后的技术

一个“提交”动作触发的操作有:binlog 落地、发送 binlog、存储引擎提交、flush_logs, check_point、事务提交标记等。这些都是数据库保证其数据完整性、持久性的手段。
在这里插入图片描述
通过原子性可以保证逻辑上的持久性,通过存储引擎的数据刷盘可以保证物理上的持久性。这个过程与前面提到的 Redo 日志、事务状态、数据库恢复、参数 innodb_flush_log_at_trx_commit 有关,还与 binlog 有关。在数据库恢复时,如果发现某事务的状态为 Prepare,则会在 binlog 中找到对应的事务并将其在数据库中重新执行一遍,来保证数据库的持久性。

隔离性

当多个事务并发访问数据库中的同一数据时,所表现出来的相互关系。
即一个事务内部的操作及使用的数据对其他的并发事务是隔离的,一个事务的执行不能被其他事务干扰

隔离性背后的技术

InnoDB 支持的隔离性有 4 种,隔离性从低到高分别为:读未提交、读提交、可重复读、可串行化。
读未提交(RU,Read Uncommitted)。它能读到一个事务的中间过程,违背了 ACID 特性,存在脏读的问题,所以基本不会用到,可以忽略。
读提交(RC,Read Committed)。它表示如果其他事务已经提交,这也是一种最普遍适用的级别。但由于一些历史原因,可能 RC 在生产环境中用的并不多。
可重复读(RR,Repeatable Read),是目前被使用得最多的一种级别。其特点是有 Gap 锁、目前还是默认的级别、在这种级别下会经常发生死锁、低并发等问题。
可串行化,这种实现方式,其实已经并不是多版本了,又回到了单版本的状态,因为它所有的实现都是通过锁来实现的,所以实际上并不是多版本控制,它的特点也很明显:读锁、单版本控制、并发低。
具体说到隔离性的实现方式,通常用 Read View 表示一个事务的可见性。 RC 级别的事务可见性比较高,它可以看到已提交的事务的所有修改。而 RR 级别的事务,则没有这个功能,一个读事务中,不管其他事务对这些数据做了什么修改,以及是否提交,只要自己不提交,查询的数据结果就不会变。
随着时间的推移,读提交每一条读操作语句都会获取一次 Read View,每次更新之后,都会获取数据库中最新的事务提交状态,也就可以看到最新提交的事务了,即每条语句执行都会更新其可见性视图。而反观下面的可重复读,这个可见性视图,只有在自己当前事务提交之后,才去更新,所以与其他事务是没有关系的。
在 RR 级别下,长时间未提交的事务会影响数据库的 PURGE 操作,从而影响数据库的性能,所以可以对这样的事务添加一个监控。

它们之间的相互关系,其中,4 个特性中有 3 个与 WAL(Write Ahead Log,顾名思义,在写数据到磁盘之前先写入log文件中) 有关系,都需要通过 Redo、Undo 日志来保证等。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值