MYSQL事务(14)

事务隔离级别的通俗解释:多人协作时的数据可见性规则

一、为什么要用隔离级别?

类比:多人同时编辑同一份文档(如在线表格)。如果没有规则,你会看到别人未保存的草稿(脏数据),或者自己的操作被覆盖。隔离级别的作用:定义不同用户操作数据的“可见范围”,平衡安全性与性能。


二、四种隔离级别及问题

隔离级别 脏读 不可重复读 幻读 性能对比 典型问题场景
读未提交 可能 可能 可能 ⚡️ 最高 用户A看到用户B未提交的订单取消,但B最终回滚
读已提交 避免 可能 可能 用户A两次查询账户余额结果不同(在事务中B提交了更新)
可重复读 避免 避免 可能* ⏱️ 中等(MySQL默认) 用户A统计订单数时,用户B新增订单导致两次统计结果不一致
串行化 避免 避免 避免 ⏳ 最低 完全避免并发问题,但事务需排队执行

⚠️ *注:MySQL的“可重复读”通过间隙锁(Gap Lock)解决了大部分幻读问题

三、隔离级别设置方法

1. 查看当前隔离级别
--查看全局隔离级别
select @@global.transaction_isolation;

--查看当前回话隔离级别
select @@session.transaction_isolation;
2. 设置全局隔离级别(需管理员权限)

set global transaction isolation level read committed;

- 持久化到配置文件(my.cnf或my.ini)
[mysqld]
transaction-isolation = READ-COMMITTED
3. 设置会话隔离级别(当前连接生效)
-- 设置为可重复读
set session transaction isolation level read committed;
4. 设置单个事务的隔离级别
-- 下一个事务将使用指定级别;
set transaction isolation level serializable
BEGIN; -- 事务开始

语法规则

  • 隔离级别名称中的空格用 - 或 _ 连接(如 READ-COMMITTED 或 READ_COMMITTED)。
  • 修改全局级别后,仅对新建立的会话生效,已存在的连接保持原级别。

四、各隔离级别的详细验证与示例

1. 读未提交(READ UNCOMMITTED)

问题验证

  • 步骤1:用户A开启事务并修改数据(不提交)。

  • START TRANSACTION;
    UPDATE account SET balance = 500 WHERE id = 1; 
    

    步骤2:用户B设置为读未提交,并查询:

  • SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    SELECT balance FROM account WHERE id = 1; -- 显示500(脏读)
    
    2. 读已提交(READ COMMITTED)

    问题验证

  • 步骤1:用户A两次查询中间,用户B更新数据并提交。
    -- 用户A事务:
    SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
    BEGIN;
    SELECT balance FROM account WHERE id = 1; -- 返回1000
    
    -- 用户B提交更新:
    UPDATE account SET balance = 800 WHERE id = 1;
    COMMIT;
    
    -- 用户A再次查询:
    SELECT balance FROM account WHERE id = 1; -- 返回800(不可重复读)
    

    应用场景:多数 OLTP 系统(如电商订单处理),需实时准确的数据。

3. 可重复读(REPEATABLE READ)

问题验证

  • 步骤1:用户A开启事务后,用户B插入新数据并提交。
-- 用户A:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT COUNT(*) FROM account WHERE balance > 1000; -- 返回3

-- 用户B:
INSERT INTO account (balance) VALUES (1500);
COMMIT;

-- 用户A再次查询:
SELECT COUNT(*) FROM account WHERE balance > 1000; -- 仍返回3(无幻读,因快照)

-- 但若用户A执行更新操作:
UPDATE account SET balance = balance - 100 WHERE balance > 1000; -- 更新包含新插入行

解决方案:MySQL的 MVCC 机制通过创建数据快照避免大部分幻读。

4. 串行化(SERIALIZABLE)

验证流程

-- 用户A:
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT * FROM account WHERE id = 1 FOR UPDATE; -- 加锁

-- 用户B尝试修改:
BEGIN;
UPDATE account SET balance = 200 WHERE id = 1; -- 阻塞,直到用户A提交

应用场景:金融核心系统(如资金清算),严格要求数据一致性。

五、隔离级别选择策略

业务需求 推荐隔离级别 理由
高并发读取,容忍误差 读已提交 平衡性能与数据可见性
数据强一致,避免幻读 可重复读 默认级别,通过快照和间隙锁控制
严格事务序列化 串行化 牺牲性能,完全避免并发问题

六、常见问题与优化

  • 锁争用处理:在高并发场景下,可重复读可能导致间隙锁冲突,可通过优化索引减少锁范围。
  • MVCC 优势:读操作无需加锁,写操作通过版本链管理,提高并发效率。
  • 死锁监控:使用 SHOW ENGINE INNODB STATUS 分析死锁日志。

你可能感兴趣的:(mysql,数据库)