更多特训营笔记详见个人主页【面试鸭特训营】专栏
241229
1. MySQL 是如何实现事务的?
事务的ACID属性
- 原子性(Atomicity):事务中的所有操作要么全都完成,要么全都不完全
- 一致性(Consistency):事务在执行前和执行后,数据库的状态必须保持一致
- 隔离性(Isolation):并发环境下不同事务相互隔离互不影响
- 持久性(Durability):事务一旦提交,对数据库的改变是永久性的,及时发生故障也不会导致改变丢失
以银行转账系统进行举例说明
在同一时刻,A要向B转账500元,C要向D转账1000元
- 原子性:【A的账户余额扣除500元】和【B的账户余额收入500元】这两件事要么全都完成,要么全都不完成,不能A扣钱了B没有收到钱
- 一致性:【A的账户余额扣除500元】和【B的账户余额收入500元】中的数据必须保持一致,不能A扣了500,B收到了400或600
- 隔离性:A给B转钱这个事,不会影响C在同一时刻给D转钱
- 持久性:【A的账户余额扣除500元】和【B的账户余额收入500元】都完成并且进行提交了之后,数据库的信息就会被永久修改,即使发生故障也可以通过恢复机制将数据库信息进行恢复
MySQL 实现事务的方案
- MySQL 通过锁机制、重做日志redo log、回滚日志undo log、MVCC实现事务
- 一致性是最终目的,通过原子性隔离性持续性实现的
锁机制
- 利用锁机制,使用数据并发修改的控制,来满足事务的隔离性
行级锁
- 新节点只对待定行的数据加锁,相比于表级锁,能够提高并发性能
- 适用于频繁的插入、更新和删除操作
表级锁
- 对整个表加锁,适用于需要报个整个表的大量读取或写入的操作
- 在某些情况下,可能导致较大的性能损失,因为其他事物无法并发访问该表
意向锁
- 是一种表级锁,用于只是特定行上的行级锁意图
- 分为意向共享锁 (IS) 和意向排他锁 (IX) ,旨在支持行级锁与表级锁的结合使用
自增锁
- 特别用于自增字段,确保在并发环境相爱自增值的唯一性
- 避免多个和事务在获取相同的自增值,造成数据不一致
共享锁
- 允许多个事务读取数据,但不允许修改
- 可用于实现读操作的并发性,确保数据在读取时的一致性
排他锁
- 只允许一个事务对数据进行读取和写入,其他事物无法读取或修改
- 保证了数据的强制控制,适用于写操作 频繁的场景
元数据锁
- 新节点用于保护数据库对象(如表和索引)的原数据
- 防止在进行 DDL 操作时其他事物对这些对象进行修改
插入意向锁
- 新节点一种特殊的意向锁,用于只是书屋打算在某个间隙中插入记录
- 允许其他事物进行共享锁,但在插入时会阻止其他的排他锁
临键锁
- 新节点是行级锁和间隙锁的结合,锁定具体行和其前面的间隙
- 确保在一个范围内不会出现幻读
- 常用于支持可重复读的隔离级别
间隙锁
- 针对索引中两个记录之间的间隙加锁
- 防止其他事物在这个间隙中插入新纪录,以避免幻读
- 间隙锁不锁定具体行,而是锁定行与行之间的空间
重做日志redo log
- 功能
- 记录事务对数据库的修改
- 在崩溃时恢复未提交的事务
- 保障事务的持久性
- 特点
- 允许系统恢复到最近的已提交状态
- 以写前日志(WAL)方式工作
回滚日志undo log
- 功能
- 记录事务的反向操作
- 保存数据的历史版本
- 用于事务的回滚
- 特点
- 在事务执行失败时恢复到之前的状态
- 保障数据的一致性与完整性
多版本并发控制MVCC
- 满足非锁定读的需求,提高并发度。实现读已提交和可重复读两种隔离级别
- 保障事务的隔离性
2. MySQL 中的 MVCC 是什么?
作用
- MVCC 是一种并发控制机制,允许多个事务同时读取和写入数据库,且无需相互等待,提高数据库并发性能
前置知识点
版本链
- 数据被修改时,MySQL 不会覆盖原数据信息,而是生成一个带有版本号和时间戳的新版本记录
- 多个版本之间串联起来,就是版本链
- 版本链支持不同时刻启动的事务可以以 无锁方式 获得不同版本的数据,读操作不会阻塞,可以读取所有已提交事务的历史版本
- 版本链支持写操作,写操作执行并该事务
提交后,新版本对其他事务可见,且未提交的事务修改不会影响其他事务的读取操作,历史版本记录可以给其他已经启动的事务提供读操作
undo log
- 回滚日志,会记录数据修改的历史信息,事务在失败或需要撤销某些操作时,可以将数据恢复到先前的状态
- 实际上索引上对应的记录只会有一个版本,即最新版本
- MVCC 所谓的多版本并不是真的存储了多个版本的数据,是借助了 undolog 记录每次写操作的反向操作
- MVCC 根据 undolog 中的记录反向操作得到数据的历史版本,所以看起来像是有多个版本,实际上只有一个版本
数据页记录
- 数据页上不仅显示存储了我们定义的字段,同时隐式存储了
trx_id和roll_pointer两个隐藏字段trx_id:当前事务idroll_pointer:指向 undo log 的指针
举例图示说明
-
现有一个空的数据表
student表,有id、name两个字段 -
执行插入语句
insert into student (id, name) values (1, '学生1') -
成功插入后数据页上不仅存储了
id = 1和name = '学生1',还有trx_id和roll_pointer两个隐藏字段-
trx_id:当前事务id -
roll_pointer:指向 undo log 的指针

-
从图中得知
- 插入的事务 ID 是2
- rool_pointer 字段指向生成的 undolog
- undolog 的类型是
TRX_UNDO_INSERT_REC,表示是 insert 生成的 - undolog 存储了主键长度和主键值(还有其他不太重要的信息),所以 Innodb 可以根据 undolog 里的主键值,找到这条记录
- 由于当前 undolog 的类型是插入类型,恢复时进行取反操作,找到这条记录后将其删除即可实现回滚
-
-
此时 事务1 提交, 然后另一个 ID 为 5 的事务执行
update name = '学生12' where id = 1语句,此时的数据记录和 undolog 如下图所示 -

-
注意以下几点
- update 产生的 undolog 的类型为
TRX_UNDO_UPD_EXIST_REC - update 产生的 undolog 中保存的数据信息与 insert 产生的 undolog 中保存的数据信息不完全一致
- insert 产生的 undolog ,在 insert 事务提交后就被回收了,因为在它之前没有更早的版本(数据信息都没有呢…),不会访问比它更早的版本了
- update 产生的 undolog ,在 update 事务提交后不会立即回收
- update 产生的 undolog 的类型为
-
此时 事务5 提交, 然后另一个 ID 为 17 的事务执行
update name = '学生123' where id = 1语句,此时的数据记录和 undolog 如下图所示-

-
注意:考虑到可能会有其他事务需要访问之前的版本,update 产生的 undolog ,在 update 事务提交后不会立即删除
-
-
这样就形成了一个版本链,可以看到【记录本身】和两条【undolog】,这条 id 为 1 的记录共有三个版本
3. MySQL 中的日志类型有哪些?binlog、redo log 和 undo log 的作用和区别是什么?
二进制日志binlog(Binary log)
- 用于记录 MySQL 服务器上所有的更新和修改操作
- MySQL 中的二进制文件
- 是逻辑日志,记录的是 SQL 语句,可以跨平台使用
- 可以记录所有的 DDL(Data Defintion Language,数据定义语言,如 create、alter、drop等) 和 DML(Data Modification Language,数据操作语言,如 intsert、update、delete) 操作,包括对表结构的更改、数据的增删改
- 在事务提交后生成,所以可以用于恢复数据库
- 可以用于主从复制、数据库恢复和审计
重做日志redolog(Redo log)
- 用于系统崩溃后恢复数据,保证数据的持久性
- MySQL 中的二进制文件
- 是物理日志,记录的是数据页的修改,不能跨平台使用
- 具体工作流程
- 当事务对数据库进行修改操作时,将这些修改记录在 Redo log 缓冲区内
- 在合适的时候(事务提交时或者缓存区满时),将缓冲区内的信息持久化到磁盘上的 Redo log 文件中
- 当系统宕机或崩溃(如断电、系统故障)时,MySQL 可以根据 Redo log 文件中记录的修改操作,在数据库重启时执行这些操作,将数据恢复到系统崩溃前已提交事务的状态
- 从而保证事物的持久性
回滚日志undolog(Undo log)
- 用于回滚操作,记录了数据修改之前的旧值,事务执行失败之后可以恢复到之前的样子,保证事务的原子性和隔离性
- 当 MySQL 发生回滚时,undolog 会记录这些操作并将其写入磁盘
- 当 MySQL 需要回滚时,通过重放 undolog 可以回滚事务
- 具体工作流程
- 当事务对数据库进行增删改操作时,将这些修改记录在 Undo log 文件中
- 在事务需要回滚时,可以根据 Undo log 文件中保存的旧值来恢复数据
- 从而保证事务的原子性
慢查询日志(slow query log)
- 记录执行时间超过一定阈值的 SQL 语句,用于优化性能
- 帮助开发者发现执行效率较低的查询
错误日志(error log)
- 记录 MySQL 服务启动、运行过程中出现的错误信息,如启动失败的原因、连接错误等
- 放比阿尼管理员进行故障排查
区别
- 记录内容
- Binary log:记录数据库基于 SQL 语句层面的底层操作,如
select name, score from student - Redo log:记录物理层面的数据页中信息的实际修改,如
某个数据页中某个字节由1变成了2 - Undo log:记录数据修改之前的旧值,用于回滚操作,如
更新操作前的原始数据信息
- Binary log:记录数据库基于 SQL 语句层面的底层操作,如
- 使用场景
- Binary log:用于数据备份、主从复制和审计
- Redo log:用于系统崩溃后恢复已提交事务,保证了事务的持久性
- Undo log:用于事务回滚,保证了事务的原子性
- 写入时机
- Binary log:事务提交后写入,可以通过配置来控制写入频率和写入方式,如
同步写入或异步写入 - Redo log:事务执行过程中写入,有多个 Redo log 文件组成一个日志组,一个文件写满后会切换到下一个文件
- Undo log:事务执行修改操作时写入,和事务生命周期相关,事务结束(提交或回滚)后,部分Undo log可能会被清理
- Binary log:事务提交后写入,可以通过配置来控制写入频率和写入方式,如
1234

被折叠的 条评论
为什么被折叠?



