1 事务
并发控制的单元,要么都做,要么都不做
redolog
- 物理日志,记录物理修改细节(崩溃不会丢)
- 核心作用:
- 崩溃恢复,commit后,内存buffer中未刷盘,重启后redo(持久性)
- 提升性能,基于wal原则,先写redolog再写数据文件
- 工作流程:
- 事务执行时,修改内存buffer pool中脏页
- 同时写入redolog buffer
- commit时,触发fsync将redolog buffer写入redo log 文件
- 后台线程异步刷盘buffer pool到磁盘ibd文件
- 细节:
- 存储形式:两个文件循环写入,
- 日志状态:prepare和commit 两阶段
- 核心参数:innodb_flush_log_at_trx_commit 控制刷盘策略
- 生命周期
- 写入:事务执行中持续添加
- 失效:redolog对应脏页被刷到数据文件后,可被覆盖
- 清理:循环写入覆盖
undolog
- 逻辑日志,记录修改前旧状态(错了能撤回)
- 核心作用:
- 事务执行失败或主动回滚时rollback(原子性)
- mvcc通过undolog找到历史版本 (隔离性 rr rc)
- 工作流程
- 事务执行dml时,先读取旧状态,写入undolog
- 若commit,undolog不会立刻删除(可能被其他事务mvcc读取)
- 若rollback,执行undolog反向操作
- 后台purge线程,异步清理(当没有事务需要读取)
- 关键细节
- 存储形式:共享表空间
- 类型:insert 提交后直接删除(无需mvcc);update delete 提交后保留,等待purge清理
- undo与rollback 通过128个rollback segment管理
- 生命周期
- 写入:执行dml时同步写入
- 保留:事务提交后标记为可清理
- 清理:purge线程定期扫描,清理过期log
acid特性
a:依赖undolog,失败时回滚
c:依赖redolog,提交时redolog刷盘,崩溃时重新修改
i:依赖undolog,mvcc读取历史版本+锁机制
d:前三点满足
2 隔离级别
为了提升mysql并发处理sql语句的性能
- ru 读未提交 隔离异常123
- rc 读已提交 读时mvcc,读取最新版本行数据 异常23
- rr 可重复度 读时mvcc,读取事务开始前快照,默认 异常3
- s
-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者采用下面的方式设置隔离级别
SET @@tx_isolation = 'REPEATABLE READ';
SET @@global.tx_isolation = 'REPEATABLE READ';
-- 查看全局隔离级别
SELECT @@global.tx_isolation;
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- 手动给读加 S 锁
SELECT ... LOCK IN SHARE MODE;
-- 手动给读加 X 锁
SELECT ... FOR UPDATE;
-- 查看当前锁信息
SELECT * FROM information_schema.innodb_locks;
3 不同隔离级别异常
- 脏读:事务B读到A未commit数据,Arollback
- 不可重复度:同一事务B两次读间隔中,Acommit了update
- 幻读:同一事务B两次查询过程中,Acommit了insert delete(范围读),导致快照读和当前读不同
4 mvcc
一致性非锁读
- readview
- rc :每次select创建
- rr:每次启动事务创建
m_ids :创建 read view 时,当前数据库活跃事务(开启未提交的事务)的事务 id 列表;
min_trx_id :创建 read view 时,m_ids 中的最小事务 id;
max_trx_id :创建 read view 时,当前数据库将为下一个事务分配的事务 id;并不一定是 m_ids
中的最大事务 id;
creator_trx_id :创建 read view 所在事务的 id
聚集索引记录的隐藏行
trx_id :当某个事务对某条聚集索引记录进行修改时,将会把当前事务的 id 赋值给 trx_id ;
roll_pointer :当某个事务对某条聚集索引记录进行修改时,会将上一个版本的记录写到 undo
log,然后通过 roll_pointer 指向旧版本记录,通过它可以找到修改前的记录
事务可见性
rc
rr
快照读
当前读
5 锁

- 锁的访问模式:s x is ix ai
- x冲突所有
- s冲突 ix ai
- ai冲突自身
锁 S X IS IX AI
S 兼容 冲突 兼容 冲突 冲突
X 冲突 冲突 冲突 冲突 冲突
IS 兼容 冲突 兼容 兼容 兼容
IX 冲突 冲突 兼容 兼容 兼容
AI 冲突 冲突 兼容 兼容 冲突
- 锁算法
- record lock 单个行记录上的锁
- gap lock 间隙锁 rr级别以上
- next-key lock r+g锁,锁定左开右闭区间
- insert intention lock 意向锁 insert 时
-- 查看是否支持间隙锁,默认支持,也就是 innodb_locks_unsafe_for_binlog = 0;
SELECT @@innodb_locks_unsafe_for_binlog
锁 G I R N 持有
GAP(请求) 兼容 兼容 兼容 兼容
Insert Intention (请求) 冲突 兼容 兼容 冲突
Record(请求) 兼容 兼容 冲突 冲突
Next-key(请求) 兼容 兼容 冲突 冲突
一个事务已经获取了插入意向锁,对其他事务是没有任何影响的;
一个事务想要获取插入意向锁,如果有其他事务已经加了 gap lock 或 Next-key lock 则会阻塞;这个是重点,死锁之源
| 维度 | record lock(记录锁) | gap lock(间隙锁) | S 锁(共享锁)/ X 锁(排他锁) |
|---|---|---|---|
| 锁定对象 | 具体的索引记录行(如 id=10 的某条数据) | 索引记录之间的间隙(如 (5,10) 区间,无实际记录) | 可作用于 record lock 或 gap lock,是锁的访问模式(共享 / 排他) |
| 核心作用 | 阻止其他事务修改或加排他锁于同一条记录 | 阻止其他事务在间隙中插入新记录,防止幻读 | - S 锁:允许多事务并发读,阻止其他事务加 X 锁; - X 锁:阻止其他事务读(加 S 锁)或写(加 X 锁) |
| 锁模式分类 | 可分为 S-record lock(共享记录锁)、X-record lock(排他记录锁) | 通常为 X-gap lock(排他间隙锁,阻止插入),也存在共享间隙锁(但场景极少) | - S 锁:共享模式,多事务可同时持有; - X 锁:排他模式,同一行仅一个事务可持有 |
| 兼容性(与自身 / 其他锁) | - 同一条记录的 S-record lock 兼容(多事务可同时加);- 与 X-record lock 冲突(同一记录仅一个 X 锁) | 同间隙的 gap lock 互相兼容(多个事务可同时加间隙锁),但与 record lock 需结合临键锁逻辑判断 | - S 锁与 S 锁兼容,与 X 锁冲突; - X 锁与 S、X 锁均冲突 |
| 典型场景 | 事务更新单条记录(如 UPDATE ... WHERE id=10) | 事务执行范围查询(如 SELECT ... WHERE id>5 FOR UPDATE),InnoDB 自动加间隙锁防止幻读 | - S 锁:SELECT ... LOCK IN SHARE MODE;- X 锁: UPDATE/DELETE 或 SELECT ... FOR UPDATE |
全局锁
表级锁:对页或表加锁
行级锁:对表的索引加锁,包括聚集索引和辅助索引
- 加锁对象 rc rr
- 聚集索引
- 辅助唯一索引
- 辅助非唯一索引
- 无索引
- 聚集索引 范围查询
6 死锁
- 相反加锁顺序死锁
- 不同表加锁顺序相反
- 相同表不同行加锁顺序相反
- 解决:调整加锁顺序
- 锁冲突死锁
- rr级别下,插入意向锁与gap锁冲突死锁
- 解决:降低隔离级别
####系统表
-- 开启标准监控
CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;
-- 关闭标准监控
DROP TABLE innodb_monitor;
-- 开启锁监控
CREATE TABLE innodb_lock_monitor (a INT) ENGINE=INNODB;
-- 关闭锁监控
DROP TABLE innodb_lock_monitor
####系统参数
-- 开启标准监控
set GLOBAL innodb_status_output=ON;
-- 关闭标准监控
set GLOBAL innodb_status_output=OFF;
-- 开启锁监控
set GLOBAL innodb_status_output_locks=ON;
-- 关闭锁监控
set GLOBAL innodb_status_output_locks=OFF;
-- 将死锁信息记录在错误日志中
set GLOBAL innodb_print_all_deadlocks=ON;
技术支持: https://github.com/0voice
639

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



