事务:https://www.cnblogs.com/kismetv/p/10331633.html
ACID:
- 原子性:undolog
- 一致性:
- 隔离性:锁
- 持久性:redolog
隔离性:
- 并发问题:
- 脏读:读到其他未提交事务的写数据,同一行
- 不可重复读:对同一行数据的查询,两次的行数据不一样
- 幻读:同样条件查询,两次的数据行数不同
- 隔离级别:
- 读未提交
- 读已提交
- 可重复读。默认
- 串行化
一个事务的写操作对另一个事务写操作的影响:加锁保证隔离性
一个事务的写操作对另一个事务读操作的影响:MVCC 保证隔离性
MVCC:Multi-Version Concurrency Control 多版本并发控制
redolog、undolog、binlog
innodb 事务日志包括 redo log 和 undo log,redo log 是重做日志,提供前滚操作,undo log 是回滚日志,提供回滚操作,其中前者保证事务的持久性,后者保证事务的原子性,两者可以统称为事务日志。
redolog 和 undolog 是 InnoDB 存储引擎是西安的 binlog 是 MySQL 的服务层实现的。同时支持其他存储引擎
redolog 和 undolog:
- https://qimok.cn/584.html
- https://www.jianshu.com/p/4bcfffb27ed5
详细:https://www.cnblogs.com/f-ck-need-u/p/9010872.html
redolog:重做日志,前滚
保证事务的持久性
- 生命周期
- 事务开始之后,就开始产生 redo log 日志了,在事务执行的过程中,redo log 开始逐步落盘,当对应事务的脏页写入到磁盘之后,redo log 的使命就完成了,它所占用的空间也就可以被覆盖了。
- 存储内容
- redo log 包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的,redo log 存储的是物理格式的日志,记录的是物理数据页面的修改信息,它是顺序写入 redo log file 中的。
- 落盘方式(将 innodb 日志缓冲区的日志刷新到磁盘)
- 1,Master Thread 每秒一次执行刷新 Innodb_log_buffer 到重做日志文件
- 2,每个事务提交时会将重做日志刷新到重做日志文件
- 3,当重做日志缓存可用空间少于一半时,重做日志缓存被刷新到重做日志文件
事务开始 -> 将修改结果更新到内存 -> 记录到 redolog,并将记录状态置为 prepare ->
- Commit 事务 -> 将 redlog 的记录置为 commit ->
- 落盘,会将 redolog 中状态为 commit 的记录的修改都写入磁盘
InnoDB 会使用缓存 Buffer Pool,来缓存磁盘数据和更新的数据,对于变化的数据,会定时刷新到磁盘(刷脏)。
如果 Buffer Pool 有还没落盘的数据,断电后就会丢失,无法保证事务的持久性,所以需要引入 redolog。
- 当修改数据时,先在 redolog 记录此次操作,然后再写入 Buffer Pool;当事务提交时,会调用 fsync 接口对 redolog 进行落盘。
- fsync 策略是可配置的:事务提交执行一次、master thread 每秒一次、事务提交只写入缓存不执行 fsync
- 如果 MySQL 宕机了,重启后仍然可以读取 redolog 的数据,对数据库进行恢复。
Q:既然事务提交后 redolog 也要写入磁盘,为什么它比直接将 Buffer Pool 刷脏要快?
A:刷脏时随机 IO,而写 redolog 是追加操作,属于顺序 IO
- 刷脏是以数据页 Page 为单位的,默认页大小为 16KB,一个 Page 上的小修改都需要整页写入;而 redolog 只写入修改部分,无效 IO 少
undolog:回滚日志,回滚
- 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供 MVCC 的读,也即非锁定读
- 生命周期:
- 事务开始之前,将当前事务版本生成 undo log,undo log 也会产生 redo log 来保证 undo log 的可靠性。当事务提交之后,undo log 并不能立马被删除,而是放入待清理的链表,由 purge 线程判断是否有其它事务在使用 undo 段中表的上一个事务之前的版本信息,从而决定是否可以清理 undo log 的日志空间。
- 存储内容:
- undo log 存储的是逻辑格式的日志,保存了事务发生之前的上一个版本的数据,可以用于回滚。当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着 undo 链找到满足其可见性的记录。
- 存储位置:
- 默认情况下,undo 文件是保存在共享表空间的,也即 ibdatafile 文件中,当数据库中发生一些大的事务性操作的时候,要生成大量的 undo log 信息,这些信息全部保存在共享表空间中,因此共享表空间可能会变得很大,默认情况下,也就是 undo log 使用共享表空间的时候,被“撑大”的共享表空间是不会、也不能自动收缩的。因此,MySQL5.7 之后的“独立 undo 表空间”的配置就显得很有必要了。
binlog:二进制日志
有了 redolog,为什么还要 binlog?
1、redolog 的大小是固定的,日志上的修改记录落盘后,日志会被覆盖掉,无法用于数据回滚/数据恢复等操作
2、redolog 是 InnoDB 引擎层实现的,并不是所有引擎都有
- binlog 是 server 层实现的,意味着所有引擎都可以使用 binlog 日志
- binlog 通过追加的方式写入,通过配置参数max_binlog_size设置每个binlog文件的大小,当文件大小大于给定值后,日志会发生滚动,之后的日志记录到新的文件上
- binlog 有两种记录模式:
- statement 格式的话是记 sql 语句
- row 格式会记录行的内容,记录两条,更新前和更新后
- mixed
binlog 和 redolog 必须保持一致。
下面是事务场景下的 binlog 和 redolog 操作:
- 先写入 redolog,状态为 prepare
- 如果失败,则执行事务回滚
- 再写入 binlog
- 如果失败了,则执行事务回滚,并撤销 redolog
- 等事务提交,将 redolog 状态置为 commit
完整流程: