概述
事务 可由一条简单的sql组成,也可有一组复杂的sql组成,事务是访问访问并更新数据库中各种数据项的一个程序执行单元。在事务的操作中,要么都在修改要么都不做。这就是事务的目的,也是事务模型区别文件系统的重要特征之一。
mysql 架构图
事务的特性
原子性(Atomicity):
作为逻辑工作单元,一个事务里的所有操作的执行,要么全部成功,要么全部失败。
一致性(Consistency):
数据库从一个一致性状态变换到另外一个一致性状态,数据库的完整性不会受到破坏。
隔离性(Isolation):
通常来说,一个事务所做的修改在最终提交前,对其他事务是不可见的。为什么是通常来说,为了提高事务的并发引出不同的隔离级别,具体参考下一章节。
持久性(Durability):
一旦事务提交,则其所做的修改就会永久保存到数据库中,即使系统故障,修改的数据也不会丢失。
mysql的日志文件
错误日志:
是对mysql的启动 运行 关闭过程进行了记录。
慢查询日志
可帮助定位可能存在的问题的sql语句。从而进行sql语言层面的优化。
查询日志
记录了所有对mysql数据库请求的信息,无论这些请求是否得到了正确的执行。
二进制日志
记录了对mysql数据库执行更改的所有操作,但不包含select 和show 这类操作。因为这类操作对数据库本身并没有修改。
InnoDB存储引擎日志文件
- redo log : 重做日志,用来保证原子性和持久性,
- undo log : 撤销日志,用来保证一致性
事务的实现 undo log和redo log
事务的自动提交
Mysql 默认采用自动提交(AUTOCOMMIT)模式,也就是说,如果不显示地开始一个事务,则每个查询都被当做一个事务执行提交操作。 可以通过以下命令查看 mysql 是否打开自动提交,
show variables like 'AUTOCOMMIT';
1、通过 set autocommit = 0 关闭当前会话的自动提交,如果需要对全局生效必须再配置文件中进行修改。
2、关闭自动提交后,用户的所有 DML 语句都会在同一个事务中,直到遇到 COMMIT 或 ROLLBACK 指令结束事务。
redo log
redo log分为2部分:
- 重做日志缓冲区(redo log buffer),内存中,易丢失
- 重做日志文件(redo log file),磁盘中,持久的。
redo log file 是顺序写入的,在数据库运行时不需要进行读取,只会在数据库启动的时候读取来进行数据的恢复工作。 redo log file 是物理日志,所谓的物理日志是指日志中的内容都是直接操作物理页的命令。重做时是对某个物理页进行相应的操作。
当mysql 发生宕机而操作系统不发生宕机当时候,并不会导致事务当丢失,而当操作系统发生宕机的时候,重启数据库会从文件系统缓存刷新到重做日志文件那部分事务。
更新事务操作一次数据的流程图如下所示:
第一步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝。
第二步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值。
第三步:在必要的时候,采用追加写的方式将 redo log buffer 中的内容刷新到 redo log file。
第四步:定期将内存中修改的数据刷新到磁盘中。
以上比较重要的是第三步,其中必要的时候有以下几种情况:
事务提交时(最常见的情景,在 commit 之前)
当 log buffer 中有一半的内存空间被使用时
log checkpoint 时
实例 shutdown 时
binlog切换时
后台线程
事务提交时将 redo log buffer 写入 redo log file,为了保证数据一定能正确同步到磁盘(不仅仅只写到文件缓冲区中)文件中,InndoDB 默认情况下调用了 fsync 进行写操作。而 fsync 的性能比较低。当然这只是默认情况,InnoDB 也提供了参数 innodb_flush_log_at_trx_commit 来配置 redo log 刷新到磁盘的策略,
上图可以更直观的说明 innodb_flush_log_at_trx_commit 不同值下的不同策略。操作越接近磁盘性能越低,当然可靠性越来越高。故性能:1 < 2 < 0,可靠性:0 < 2 < 1。
当 innodb_flush_log_at_trx_commit 设置为 0 或者 2 时丧失了事务的 ACID 特性,通常在日常环境时将其设置为 1,而在系统高峰时将其设置为 2 以应对大负载。
undo log
- undo log 用来实现事务的一致性,InndoDB 可以通过 redo log 对页进行重做操作。但是有时候事务需要进行回滚,这时就需要 undo log。
- undo log 还可可以用来协助 InnoDB 引擎实现 MVCC 机制。
- undo log 是逻辑日志,恢复时并不是对物理页直接进行恢复,而是逻辑地将数据库恢复到原来的样子。
- undo log 的产生也会伴随着 redo log 的产生。
写入对时机:
undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。
事务间的隔离
与原子性、持久性、一致性 侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。
隔离性追求的是并发情形下事务之间互不干扰。
锁机制
锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据;该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。
- 行锁和表锁
按照粒度,锁可以分为表锁、行锁,例如MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。 - 共享锁和排他锁
InnoDB 实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)。
共享锁(S锁):允许持锁事务读取一行。
排他锁(X锁):允许持锁事务更新或者删除一行。
隔离级别
在实际应用中,读未提交在并发时会导致很多问题,而性能相对于其他隔离级别提高却很有限,因此使用较少。可串行化强制事务串行,并发效率很低,只有当对数据一致性要求极高且可以接受没有并发时使用,因此使用也较少。因此在大多数数据库系统中,默认的隔离级别是读已提交(RC)(如Oracle)或可重复读(RR)。mysql 是 可重复读。
MVCC
RR解决脏读、不可重复读、幻读等问题,使用的是MVCC:MVCC全称Multi-Version Concurrency Control,即多版本的并发控制协议。
它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。它的实现依赖于隐式字段、undo日志、快照读&当前读、Read View.
MVCC最大的优点是读不加锁,因此读写不冲突,并发性能好。InnoDB实现MVCC,多个版本的数据可以共存,主要是依靠数据的隐藏列(也可以称之为标记位)和undo log。其中数据的隐藏列包括了该行数据的版本号、删除时间、指向undo log的指针等等;当读取数据时,MySQL可以通过隐藏列判断是否需要回滚并找到回滚需要的undo log,从而实现MVCC........
参考:
详细分析mysql事务日志
十分钟搞懂MySQL四种事务隔离级别
Mysql 事务-你想知道都在这
一文彻底读懂MySQL事务的四大隔离级别
脏读 幻读 不可重复度