文章中如果有图看不到,可以点这里去 csdn 看看。从那边导过来的,文章太多,没法一篇篇修改好。

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);
}

六、实战建议

  1. 长事务风险

    • Undo Log堆积 → 回滚段膨胀
    • 解决方案:监控 information_schema.innodb_trx,设置 innodb_max_undo_log_size
  2. 死锁处理

    SHOW ENGINE INNODB STATUS; -- 查看最新死锁信息
    SET GLOBAL innodb_print_all_deadlocks = 1; -- 记录所有死锁到错误日志
    
  3. 性能优化

    • 避免 SELECT ... FOR UPDATE 全表扫描(升级为表锁)
    • 二级索引访问时,主键索引仍会加锁

通过以上解析可见,MySQL事务实现是日志系统(Redo/Undo)、锁系统、MVCC三者的精密协作。理解其底层机制对处理高并发事务、数据一致性保障及性能调优至关重要。

posted @ 2025-08-31 20:22  NeoLshu  阅读(2)  评论(0)    收藏  举报  来源