MySQL 事务知识点大全【ACID、隔离级别、MVCC、锁应用】
一、事务核心原理:ACID实现机制
1. 原子性(Atomicity)
- 实现机制:Undo Log(回滚日志)
- 原理:
- 每个写操作前先在Undo Log中记录数据旧版本
- 事务失败时执行
ROLLBACK,通过Undo Log恢复数据
- 源码关键点(
storage/innobase/trx/trx0undo.cc):// 写入undo记录 trx_undo_report_row_operation(/*...*/) { // 将旧值写入undo log buffer trx_undo_page_report_modify(/*...*/); // 构建回滚指针链 row_upd_index_entry_set_roll_ptr(/*...*/); }
2. 持久性(Durability)
- 实现机制:Redo Log + Doublewrite Buffer
- 原理:
- 事务提交前先写Redo Log(顺序写高性能)
- Doublewrite Buffer防止页断裂(partial page write)
- 刷盘流程(源码
storage/innobase/log/log0write.cc):log_write_up_to(lsn_t lsn) { // 1. 将log buffer写入OS cache write_to_log_file(log.buffer); // 2. 触发fsync()刷盘(innodb_flush_log_at_trx_commit=1时) fil_flush_file_sync(log.file); }
3. 隔离性(Isolation)
- 实现机制:MVCC + 锁系统
- MVCC:通过ReadView实现快照读
- 锁系统:行锁(Record Lock)、间隙锁(Gap Lock)、Next-Key Lock
- 源码关键结构(
storage/innobase/include/read0types.h):struct ReadView { ids_t m_ids; // 活跃事务ID列表 trx_id_t m_low_limit_id; // 高水位线(大于此值的事务不可见) // 判断事务是否可见 bool changes_visible(trx_id_t id) const { return id < m_up_limit_id || (id >= m_low_limit_id ? false : !m_ids.contains(id)); } };
4. 一致性(Consistency)
- 实现机制:由原子性、隔离性、持久性共同保证
- 额外机制:InnoDB的doublewrite(
storage/innobase/dblwr/dblwr0.cc)防止页断裂
二、事务隔离级别与问题复现
事务提交和崩溃恢复流程示意图

示例表结构:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(20),
balance DECIMAL(10,2)
) ENGINE=InnoDB;
1. 脏读(Read Uncommitted)
-- Session A
SET tx_isolation = 'READ-UNCOMMITTED';
START TRANSACTION;
UPDATE users SET balance = balance + 100 WHERE id = 1; -- 未提交
-- Session B(读到未提交数据)
SET tx_isolation = 'READ-UNCOMMITTED';
SELECT balance FROM users WHERE id = 1; -- 看到+100后的结果
2. 不可重复读(Read Committed)
-- Session A
START TRANSACTION;
SELECT balance FROM users WHERE id = 1; -- 值=100
-- Session B
UPDATE users SET balance = 200 WHERE id = 1;
COMMIT;
-- Session A再次读取(值变为200)
SELECT balance FROM users WHERE id = 1;
3. 幻读(Repeatable Read解决方案)
-- Session A
START TRANSACTION;
SELECT * FROM users WHERE id > 10; -- 返回2条记录
-- Session B
INSERT INTO users VALUES (15, 'new', 500); -- 成功插入
COMMIT;
-- Session A(RR级别下看不到新记录)
SELECT * FROM users WHERE id > 10; -- 仍返回2条
三、MVCC实现深度解析
MVCC 原理示意图

1. 隐藏字段
每行记录包含:
DB_TRX_ID:最后修改的事务ID(6字节)DB_ROLL_PTR:回滚指针(7字节),指向Undo Log
2. ReadView生成时机
- RC:每次SELECT生成新ReadView
- RR:第一次SELECT生成ReadView,后续复用
3. 数据可见性判断流程
def row_is_visible(row, read_view):
if row.trx_id < read_view.up_limit_id:
return True # 事务已提交
elif row.trx_id >= read_view.low_limit_id:
return False # 事务未开始或修改后
else:
return row.trx_id not in read_view.active_ids # 是否在活跃事务中
四、锁机制源码解析
1. 行锁结构(storage/innobase/include/lock0lock.h)
struct lock_rec_t {
space_id_t space; // 表空间ID
page_no_t page_no; // 页号
uint32_t n_bits; // 锁位图大小
byte* bits; // 锁位图(标记被锁记录)
};
2. Next-Key Lock加锁流程

// storage/innobase/lock/lock0lock.cc
lock_rec_lock(...) {
// 1. 检查是否已有兼容锁
if (lock_rec_has_expl(/*...*/)) return;
// 2. 创建锁对象
lock_t* lock = lock_rec_create(/*...*/);
// 3. 设置锁类型(LOCK_X | LOCK_GAP等)
lock_rec_set_nth_bit(lock, heap_no);
}
五、事务提交过程源码级分析
// storage/innobase/trx/trx0trx.cc
trx_commit(trx_t* trx) {
// 1. 生成Redo Log
trx_write_serialisation_history(trx);
// 2. 刷Redo Log(关键持久化点)
log_buffer_flush_to_disk();
// 3. 释放锁
lock_release(trx);
// 4. 清理Undo Log(后台purge线程)
trx_purge_add_undo_to_history(trx);
}
六、实战建议
-
长事务风险:
- Undo Log堆积 → 回滚段膨胀
- 解决方案:监控
information_schema.innodb_trx,设置innodb_max_undo_log_size
-
死锁处理:
SHOW ENGINE INNODB STATUS; -- 查看最新死锁信息 SET GLOBAL innodb_print_all_deadlocks = 1; -- 记录所有死锁到错误日志 -
性能优化:
- 避免
SELECT ... FOR UPDATE全表扫描(升级为表锁) - 二级索引访问时,主键索引仍会加锁
- 避免
通过以上解析可见,MySQL事务实现是日志系统(Redo/Undo)、锁系统、MVCC三者的精密协作。理解其底层机制对处理高并发事务、数据一致性保障及性能调优至关重要。
本文来自博客园,作者:NeoLshu,转载请注明原文链接:https://www.cnblogs.com/neolshu/p/19120891

浙公网安备 33010602011771号