MySQL事务隔离级别

MySQL事务隔离级别

事务四大特性(ACID)

特性 说明 MySQL 实现方式
原子性 (Atomicity) 事务要么全部完成,要么全部不完成 Undo Log(回滚日志)
一致性 (Consistency) 事务前后数据完整性一致 业务逻辑 + 数据库约束
隔离性 (Isolation) 事务之间互不干扰 MVCC + 锁机制
持久性 (Durability) 事务提交后永久生效 Redo Log(重做日志)
e9c96c2ca82cdcef35ea2fe411685110

四种隔离级别

1. READ UNCOMMITTED(读未提交)

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

特点:

  • 可以读取其他事务未提交的数据
  • 脏读、不可重复读、幻读 都可能发生

使用场景:

  • 对数据一致性要求极低的场景
  • 统计类查询(如 count(*),允许一定的数据偏差)
  • 实际生产环境几乎不使用

示例:

-- 事务A
BEGIN;
UPDATE accounts SET balance = 500 WHERE id = 1;  -- 未提交

-- 事务B(READ UNCOMMITTED)
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  -- 读到500(脏读)

2. READ COMMITTED(读已提交)

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

特点:

  • 只能读取其他事务已提交的数据
  • 解决脏读,但仍存在不可重复读、幻读
  • Oracle、PostgreSQL 的默认级别

实现原理:

  • 每次 SELECT 都生成新的 ReadView
  • 使用 MVCC 读取最新已提交版本

示例:

-- 事务A
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  -- 返回100

-- 事务B
BEGIN;
UPDATE accounts SET balance = 200 WHERE id = 1;
COMMIT;  -- 提交

-- 事务A再次读取
SELECT balance FROM accounts WHERE id = 1;  -- 返回200(不可重复读)

3. REPEATABLE READ(可重复读)MySQL默认

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

特点:

  • 同一事务内多次读取结果一致
  • 解决脏读、不可重复读,部分解决幻读
  • MySQL InnoDB 默认隔离级别

实现原理:

  • 第一次 SELECT 时生成 ReadView,后续复用
  • 使用 Next-Key Lock(临键锁)防止部分幻读

示例:

-- 事务A
BEGIN;
SELECT * FROM accounts WHERE balance > 100;  -- 返回id=1,2

-- 事务B
BEGIN;
INSERT INTO accounts(id, balance) VALUES(3, 200);  -- 会被阻塞(Next-Key Lock)
COMMIT;

-- 事务A再次读取
SELECT * FROM accounts WHERE balance > 100;  -- 仍只返回id=1,2(快照读)

4. SERIALIZABLE(串行化)

SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

特点:

  • 完全串行执行,性能最差
  • 解决所有并发问题(脏读、不可重复读、幻读)
  • 通过锁机制而非 MVCC 实现

实现原理:

  • 所有 SELECT 自动转为 SELECT ... LOCK IN SHARE MODE
  • 读写完全互斥

示例:

-- 事务A
BEGIN;
SELECT * FROM accounts WHERE id = 1;  -- 自动加共享锁

-- 事务B
BEGIN;
UPDATE accounts SET balance = 300 WHERE id = 1;  -- 被阻塞,等待事务A释放锁

MySQL 实现机制详解

1. MVCC(多版本并发控制)

-- 隐藏字段(每行数据)
DB_TRX_ID    -- 最近修改的事务ID(6字节)
DB_ROLL_PTR  -- 回滚指针,指向undo log(7字节)
DB_ROW_ID    -- 隐藏自增ID(6字节)

-- Undo Log 版本链
当前行 → undo_v1 → undo_v2 → undo_v3

2. ReadView(读视图)

// ReadView 结构
class ReadView {
    List
<Long> m_ids;          // 活跃事务ID列表
    Long min_trx_id;           // 最小活跃事务ID
    Long max_trx_id;           // 预分配的下一个事务ID
    Long creator_trx_id;       // 创建该ReadView的事务ID
}

3. 锁机制

-- 记录锁(Record Lock)
-- 锁定单条记录

-- 间隙锁(Gap Lock)
-- 锁定记录之间的间隙,防止插入
SELECT * FROM users WHERE age > 20 FOR UPDATE;

-- 临键锁(Next-Key Lock = Record Lock + Gap Lock)
-- RR级别默认使用,防止幻读
-- 锁定记录本身和前面的间隙

不同隔离级别的实现差异

RC vs RR 的 ReadView 创建时机

-- READ COMMITTED:每次SELECT都新建ReadView
function read_committed_read() {
    create_new_readview();  // 每次新建
    find_visible_version();
}

-- REPEATABLE READ:第一次SELECT时创建,后续复用
function repeatable_read() {
    if (first_read_in_transaction) {
        create_readview();  // 只创建一次
    }
    find_visible_version();  // 复用同一个ReadView
}

幻读解决方案对比

-- 情况:查询age>20的记录

-- RC级别:可能幻读
BEGIN;  -- RC级别
SELECT * FROM users WHERE age > 20;  -- 返回3条
-- 另一个事务插入age=25的记录
SELECT * FROM users WHERE age > 20;  -- 返回4条(幻读)

-- RR级别:通过Next-Key Lock防止
BEGIN;  -- RR级别
SELECT * FROM users WHERE age > 20 FOR UPDATE;  -- 加Next-Key Lock
-- 锁住20到正无穷的间隙,其他事务无法插入

配置与监控

查看和设置隔离级别

-- 查看当前隔离级别
SELECT @@transaction_isolation;
SELECT @@global.transaction_isolation;
SELECT @@session.transaction_isolation;

-- 设置全局隔离级别
SET GLOBAL transaction_isolation = 'REPEATABLE-READ';

-- 设置会话隔离级别
SET SESSION transaction_isolation = 'READ-COMMITTED';

监控事务相关指标

-- 查看当前运行的事务
SELECT * FROM information_schema.innodb_trx;

-- 查看锁信息
SELECT * FROM information_schema.innodb_locks;
SELECT * FROM information_schema.innodb_lock_waits;

-- 查看事务历史
SELECT * FROM performance_schema.events_transactions_current;
SELECT * FROM performance_schema.events_transactions_history;

my.cnf 配置建议

[mysqld]
# 默认隔离级别
transaction-isolation = REPEATABLE-READ

# 锁相关配置
innodb_lock_wait_timeout = 50          # 锁等待超时(秒)
innodb_rollback_on_timeout = ON        # 超时自动回滚

# MVCC相关配置
innodb_undo_logs = 128                 # undo log数量
innodb_purge_threads = 4               # purge线程数
innodb_max_purge_lag = 900000          # 最大purge延迟

实际应用建议

1. 选择合适隔离级别

-- 大多数场景:使用默认的 REPEATABLE READ
-- 高并发读场景:考虑 READ COMMITTED
-- 财务系统:可能需要 SERIALIZABLE

2. 事务设计

-- 保持事务短小
BEGIN;
-- 尽可能少的SQL操作
COMMIT;

-- 按相同顺序访问表,避免死锁

3. 性能优化技巧

-- RC级别可以减少锁冲突
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 合理使用索引,减少锁范围
CREATE INDEX idx_age ON users(age);
SELECT * FROM users WHERE age = 25 FOR UPDATE;  -- 只锁age=25的行

-- 分批处理大数据量更新
UPDATE large_table SET status = 1 WHERE id BETWEEN 1 AND 1000;
UPDATE large_table SET status = 1 WHERE id BETWEEN 1001 AND 2000;
隔离级别 MySQL 实现 适用场景 注意事项
READ UNCOMMITTED 直接读取最新数据 几乎不用 数据一致性无要求
READ COMMITTED 每次新建 ReadView 高并发读,可接受不可重复读 适合读多写少
REPEATABLE READ 首次 SELECT 建 ReadView + Next-Key Lock 默认选择,大部分场景 平衡性能与一致性
SERIALIZABLE 所有读加共享锁 强一致性要求,如金融系统 性能最差

要点:

  1. MySQL 默认使用 REPEATABLE READ,通过 MVCC + Next-Key Lock 实现
  2. 隔离级别越高,并发性能越低
  3. 理解实现原理有助于设计更好的应用和解决并发问题
  4. 实际选择需权衡数据一致性系统性能需求

注意:

  • mysql 事务隔离级别是指在数据库中,不同事务之间的隔离程度。
  • 不同的隔离级别对应不同的并发性能和数据一致性。
  • mysql 提供了四种事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。
  • 默认隔离级别是 REPEATABLE READ。
  • 如果在默认隔离级别事务中查询数据并且读取,这里需要注意,并行事务间的数据操作是不可读不可见的,只能读取到事务开始时的数据。

www.ierchina.com/

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top