11_MySQL事务和事务日志

系列文章目录

第1章 MySQL系列文章之子查询
第2章 MySQL系列文章之表的操作和约束
第3章 MySQL系列文章之表的视图和存储过程
第4章 MySQL系列文章之逻辑架构
第5章 MySQL系列文章之存储引擎
第6章 MySQL系列文章之索引的数据结构
第7章 MySQL系列文章之索引的创建与设计原则
第8章 MySQL系列文章之索引的性能分析工具的使用
第9章 MySQL系列文章之索引优化与查询优化
第10章 MySQL系列文章之数据库其它调优策略
第11章 MySQL事务和事务日志
第12章 MySQL的锁
第13章 MySQL的多版本并发控制
第14章 MySQL日志和主从复制
第15章 基于Docker的MySQL备份

一、事务概述

1.1、事务概念

事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。
事务处理的原则:当在一个事务中执行多个操作时,要么所有的事务都被提交( commit ),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚( rollback )到最初状态。

1.2、事务ACID特性

  • 原子性(atomicity):原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
  • 一致性(consistency):事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。满足预定的约束的状态就叫做合法的状态。满足这个状态,数据就是一致的,不满足这个状态,数据就是不一致的!
  • 隔离型(isolation):一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(durability):事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

二、使用事务

2.1、显式事务

1、开启事务

BEGIN;
#或
START TRANSACTION;

2、事务中的操作

3、提交事务 或 中止事务

COMMIT;#提交事务。当提交事务后,对数据库的修改是永久性的。
#或
ROLLBACK;#回滚事务。即撤销正在进行的所有没有提交的修改

2.1、隐式事务

查看隐式事务是否开启:

SHOW VARIABLES LIKE 'autocommit';

设置隐式事务开启:

SET autocommit = ON;

什么时候会自动提交?
1、在一个事务还没提交或回滚时,又使用BEGIN 等语句开启了新事务时,会隐式的提交上一个事务。
2、手动把autocommit变量从OFF调为ON 时,也会隐式的提交前边语句所属的事务。
3、使用LOCK TABLES 、UNLOCK TABLES 等关于锁定的语句也会隐式的提交前边语句所属的事务。

三、事务并发问题和隔离级别

3.1、数据并发问题

  • 脏写: 事务A 修改了事务B 修改过但未提交的数据。
  • 脏读: 事务A 读取了事务B 修改过但未提交的数据。
  • 不可重复读: 事务A 读取了一个字段,然后 事务B 更新了该字段。 之后事务A 再次读取同一个字段, 值就不同了。
  • 幻读: 事务A 从一个表中读取了一个字段, 然后 事务B 在该表中插入了一些新的行。 之后事务A 再次读取同一个表, 就会多出几行

3.2、四种隔离级别

  • 读未提交(READ UNCOMMITTED):所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。
  • 读已提交(READ COMMITTED):一个事务只能看见已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。
  • 可重复读(REPEATABLE READ):事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别
  • 可串行化(SERIALIZABLE):在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。

四、redo日志

4.1、日志和事务特性的关系

  • 隔离性由锁机制实现
  • 原子性、一致性由undo log(回滚日志)保证
  • 持久性由redo log(重做日志)保证

4.2、redo日志的好处、作用

  • redo日志降低了刷盘频率:为了保证持久性,需要将数据页变化刷新到硬盘。刷盘非常消耗资源,为了减少这种消耗,可以将数据页的变化记录到redo log,等数据页更新到一定程度再进行刷盘。
  • redo日志占用的空间非常小

4.3、redo log的刷盘策略

redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中。
整体流程:
在这里插入图片描述
redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。
针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit 参数,该参数控制 commit提交事务
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:

  • 设置为0 :事务提交时不进行刷盘操作(系统默认master thread每隔1s进行一次重做日
    志的同步)
  • 设置为1 :事务提交时都进行刷盘操作( 默认值)
  • 设置为2 :事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由系统决定何时同步到磁盘文件。

4.4、相关参数设置

  • innodb_log_group_home_dir :指定 redo log 文件组所在的路径,默认值为./ ,表示在数据库的数据目录下。MySQL的默认数据目录( var/lib/mysql )下默认有两个名为ib_logfile0 和ib_logfile1 的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。
  • innodb_log_files_in_group:指明redo log file的个数,命名方式。如:ib_logfile0,iblogfile1…iblogfilen。默认2个,最大100个。
  • innodb_flush_log_at_trx_commit:控制 redo log 刷新到磁盘的策略,默认为1。
  • innodb_log_file_size:单个 redo log 文件设置大小,默认值为 48M 。最大值为512G,注意最大值指的是整个 redo log 系列文件之和,即(innodb_log_files_in_group * innodb_log_file_size )不能大于最大值512G。

五、undo日志

5.1、Undo日志的作用

undo log是一种用于撤销回退的日志,在事务没提交之前,MySQL会先记录更新前的数据到 undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退。

1、回滚数据,实现事务的原子性
如我们执行下面一条删除语句:

delete from user where id = 1;

那么此时undo log会记录一条对应的insert 语句【反向操作的语句】,以保证在事务回滚时,将数据还原回去。

再比如我们执行一条update语句:

update user set name = "李四" where id = 1;   ---修改之前name=张三

此时undo log会记录一条相反的update语句,如下:

update user set name = "张三" where id = 1;

如果这个修改出现异常,可以使用undo log日志来实现回滚操作,以保证事务的一致性。

2、 MVCC,实现多版本并发控制
MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】

下面解释一下什么是快照读,与之对应的还有一个是—当前读。

快照读:

SQL读取的数据是快照版本【可见版本】,也就是历史版本,不用加锁,普通的SELECT就是快照读。

当前读:

SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是当前读。

5.2、回滚段与事务

  1. 每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。
  2. 当一个事务开始的时候,会制定一个回滚段,在事务进行的过程中,当数据被修改时,原始的数据会被复制到回滚段。
  3. 在回滚段中,事务会不断填充盘区,直到事务结束或所有的空间被用完。

5.3、undo log的存储机制

undo log的存储由InnoDB存储引擎实现,数据保存在InnoDB的数据文件中。在InnoDB存储引擎中,undo log是采用分段(segment)的方式进行存储的。rollback segment称为回滚段,每个回滚段中有1024个undo log segment。在MySQL5.5之前,只支持1个rollback segment,也就是只能记录1024个undo操作。在MySQL5.5之后,可以支持128个rollback segment,分别从resg slot0 - resg slot127,每一个resg slot,也就是每一个回滚段,内部由1024个undo segment 组成,即总共可以记录128 * 1024个undo操作。

下面以一张图来说明undo log日志里面到底存了哪些信息?

在这里插入图片描述
如上图,可以看到,undo log日志里面不仅存放着数据更新前的记录,还记录着RowID、事务ID、回滚指针。其中事务ID每次递增,回滚指针第一次如果是insert语句的话,回滚指针为NULL,第二次update之后的undo log的回滚指针就会指向刚刚那一条undo log日志,依次类推,就会形成一条undo log的回滚链,方便找到该条记录的历史版本。

5.4、undo log的工作原理

在更新数据之前,MySQL会提前生成undo log日志,当事务提交的时候,并不会立即删除undo log,因为后面可能需要进行回滚操作,要执行回滚(rollback)操作时,从缓存中读取数据。undo log日志的删除是通过通过后台purge线程进行回收处理的。

同样,通过一张图来理解undo log的工作原理。
在这里插入图片描述

如上图:

1、事务A执行update操作,此时事务还没提交,会将数据进行备份到对应的undo buffer,然后由undo buffer持久化到磁盘中的undo log文件中,此时undo log保存了未提交之前的操作日志,接着将操作的数据,也就是Teacher表的数据持久保存到InnoDB的数据文件IBD。
2、此时事务B进行查询操作,直接从undo buffer缓存中进行读取,这时事务A还没提交事务,如果要回滚(rollback)事务,是不读磁盘的,先直接从undo buffer缓存读取。

用undo log实现原子性的事务的简化过程:

假设有A、B两个数据,值分别为1,2。

  • A. 事务开始
  • B. 记录A=1到undo log中
  • C. 修改A=3
  • D. 记录B=2到undo log中
  • E.修改B=4
  • F. 将undo log写到磁盘 -------undo log持久化
  • G. 将数据写到磁盘-------数据持久化
  • H. 事务提交 -------提交事务

之所以能同时保证原子性和持久化,是因为以下特点:

更新数据前记录undo log。
为了保证持久性,必须将数据在事务提交前写到磁盘,只要事务成功提交,数据必然已经持久化到磁盘。
undo log必须先于数据持久化到磁盘。如果在G,H之间发生系统崩溃,undo log是完整的,可以用来回滚。
如果在A - F之间发生系统崩溃,因为数据没有持久化到磁盘,所以磁盘上的数据还是保持在事务开始前的状态。

缺陷:每个事务提交前将数据和undo log写入磁盘,这样会导致大量的磁盘IO,因此性能较差。 如果能够将数据缓存一段时间,就能减少IO提高性能,但是这样就会失去事务的持久性。

undo日志属于逻辑日志,redo是物理日志,所谓逻辑日志是undo log是记录一个操作过程,不会物理删除undo log,sql执行delete或者update操作都会记录一条undo日志。

5.5、undo log的相关参数

innodb_undo_directory

指定undo log日志的存储目录,默认值为./。

 innodb_undo_logs 

在MySQL5.6版本之后,可以通过此参数自定义多少个rollback segment,默认值为128。

 innodb_undo_tablespaces 

指定undo log平均分配到多少个表空间文件中,默认值为0,即全部写入一个文件中。不建议修改为非0值,我们直接使用默认值即可。

小结

日志

  • undo log是逻辑日志,对事务回滚时,只是将数据库逻辑地恢复到原来的样子。
  • redo log是物理日志,记录的是数据页的物理变化,undo log不是redo log的逆过程。

参考:
1、MySQL高级特性篇-宋红康
2、https://blog.csdn.net/Weixiaohuai/article/details/117867353

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值