1. 什么是事务?
事务是一组 SQL语句的集合,要么全部执行,要么全部不执行。
事务有四大特性ACID: 原子性,一致性,隔离性,持久性
原子性:一个事务的操作要么全部执行,要么全部不执行。在事务的执行过程中,发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过 一样。主要是靠undolog进行保证的
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力。事务隔离级别分为不同的级别:读未提交(Read uncommited),读已提交(Read commited),可重复读(Repeatable read)和串行化(Serializable)主要是靠MVCC进行保证的
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。主要是靠redolog进行实现的
以上三个特性可以保证 一致性:在事务开始之前和事务结束之后,数据库的完整性没有破坏。
0. SQL的各个日志是干什么用的?
SQL中主要有:
errlog: 错误日志
binlog: 主从复制,主从同步
slowlog: 慢日志
relaylog: 中继日志
以上日志是位于server层面的,和存储引擎无关。
innodb有两个独有的日志,一个是
undolog:回滚日志,记录数据被修改前的样子
redulog:前滚日志,记录的是数据修改之后的值,不管事务是否提交都会记录下来
1. undolog是干什么的?
作用: 防止丢失数据,用于事务失败后的回滚。
记录时机: 在mysql将更新的数据加载到缓冲区Buffer pool时,同时往undolog中插入一条日志,也就是将id=1的这条记录的原来的值记录下来。
更新时机:
- 准备一条SQL语句
- MySQL(Innodb)会先去缓冲池(Buffer pool)中查找这条数据,没找到就回去磁盘中查找,如果查找到就会将这条数据加载到缓存池(Buffer pool)
- 在加载到Buffer Pool 的同时,会将这条数据的原始记录保存到undo日志文件中
问题:当Buffer Pool中的数据和数据库中的数据不一致时,我们就会认为缓存中的数据时脏数据。
2. redolog是干什么的?
作用: redolog记录的是数据修改之后的值,不管事务是否提交都会记录下来
- redolog是Innodb特有的,他是存储引擎级别的,不是mySql server级别的
- 服务器宕机,mysql重启时,利用redolog日志内容恢复到缓冲区数据
- 一般情况下,redolog Buffer数据写入磁盘的策略是立即刷入磁盘
2.1 为什么需要redolog
- Mysql为了提高效率,所以先从磁盘读取数据放在内存中去完成,然后直接对内存进行数据的操作,这些操作会在某个时机将其持久化到磁盘中。
- 除了从磁盘中加载文件和将操作前的记录保存在undolog中,其他操作都是在内存中完成的
- 内存数据断电丢失:如果此时MySQL所在的服务器宕机了,那么Buffer Pool中的数据会全部丢失。这个时候就需要redolog来恢复数据
2.2 redolog的刷写时机
刷磁盘可以通过 innodb_flush_log_at_trx_commit 参数来设置
值为 0 表示不刷入磁盘 值为 1 表示立即刷入磁盘(默认情况) 值为 2 表示先刷到 os cache
一般情况下,redo log Buffer 数据写入磁盘的策略是立即刷入磁盘
3. binlog是干什么的?
用于记录数据库执行的写入性操作(DDL,DML,不包括查询)信息,以二进制的形式保存在磁盘中。
binlog是以追加的形式写入的。
3.1 使用场景
在实际应用中,binlog的主要使用场景由两个,分别是主从复制和数据恢复
- 主从复制:在Master端开启binlog,然后将binklog发送到各个Slave端,Slave端重发binlog从而达到主从数据一致。
- 数据恢复:通过mysqlbinlog工具来恢复数据
mysql通过sync_binlog参数控制biglog的刷盘时机,取值范围是0-N:
0:先写入 os cache,由系统自行判断何时写入磁盘,宕机数据会丢失;(MySQL 5.7.7之前版本的默认值) 1:每次commit的时候都要将binlog写入磁盘;(MySQL 5.7.7之后版本的默认值) N:每N个事务,才会将binlog写入磁盘。
3.2 binlog刷写磁盘策略
对于InnoDB存储引擎而言,只有在事务提交时才会记录binlog
4. 准备更新到事务提交全过程
- 首先执行器根据 更新sql,来查询满足条件的数据,先是从缓存池中查询数据,如果没有就会在数据库中查询,如果查询到了将其放到缓存池中
- 在数据被缓存到缓存池的同时,将原始数据写入undolog文件中
- 在Buffer Pool中更新数据,将更新后的数据添加到redo log buffer中
- 完成以后就可以提交事务,在提交事务前会做以下三件事
将redo log buffer 的数据持久化到 redolog文件中 将本次操作记录持久化到binlog日志文件中 将binlog记录结束的位置标记记录到redolog中,最后在redolog添加commit标记(表示事务完成)
4.1 两阶段提交
- 写入 redo log,处于 prepare 状态。
- 写 binlog。
- 修改 redo log 状态变为 commit。
由于 redo log 的提交分为 prepare 和 commit 两个阶段,所以称之为两阶段提交。
4.2 为什么需要两阶段提交?
如果没有两阶段提交的话,那就是一阶段提交,就两种形式
- 先提交binlog,再提交redolog
- 先提交redolog,再提交binlog
当我们要想表中插入一条记录R,先写binlog,再写redolog。但是写完binlog后,突然发生了断电。具体操作已经同步binlog保存了起来,但是没有保存操作过后的数据。然后来电后,机子开始进行恢复的操作,binlog中已经有R的记录了,当从机从主机同步数据的是时候,或者我们使用binlog恢复数据的时候,就会同步到R这条记录;但是redolog中没有关于R的记录,所以崩溃恢复之后,插入R记录的这个事务是无效的,即数据库中没有该行记录,这就造成了数据不一致。
当我们要想表中插入一条记录R,先写redolog,再写binlog。但是写完redolog后,突然发生了断电。机子开机再恢复的过程中就会出现问题:redolog中是有数据R的,所以在恢复数据库的时候将该条数据恢复到数据库中。但是binlog中是没有关于R的数据的,所以当从机从主机同步数据的时候或者我们使用binlog恢复数据的时候,就不会同步到R这条记录,这也就造成了数据不一致。
5. 数据库支持的几种并发情况
读读,读写,写写
读读: 不存在任何问题,也不需要并发控制 读写: 有数据安全问题,会出现脏读,不可重复读,幻读,依靠MVCC解决 写写: 有数据安全问题,会存在丢失更新的问题,锁来解决
6. 什么是MVCC?
MVCC:Multi-Version Concurrency Control,多版本并发控制,用来解决并发读写问题,不需要通过加锁来解决。 MVCC本质上是维持了一个数据的多个版本,使得读写操作之间没有冲突。 MVCC只在RC 和 RR 两个隔离级别下工作
6.1 当前读和快照读
当前读: 读取的是数据的最新版本,而且要保证其他并发事务不能修改当前记录,for update ,update ,delete ,insert 快照读:不加锁的非阻塞读,读取的是历史版本的数据,不是最新的记录。不加锁的select
6.2 RC 和 RR
RC读已提交:当其他事务修改数据之后,可以看的修改之后的值,每一次进行一次快照读,都会生成新的readview RR可重复读:当其他事务修改数据之后,看不到修改之后的值,每个事务只有在第一次进行快照读的时候会生成readview,之后的快照读都会沿用之间的readview
不同的隔离级别生成的readview的时机是不同的
6.3 RR隔离级别能否解决幻读问题?
不能
幻读: 一个事务读取到了另一个数据插入进来的数据。 出现的本质原因是: 如果事务中都是用快照读,那么是不会产出幻读的,但是当快照读和当前读一起使用的时候就产生了幻读问题。
参考
直播笔记 MySQL-三大日志详解 MySQL 事务-菜鸟教程 MySQL 为什么需要两阶段提交?
|