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