事务的四大特性(ACID)和隔离级别

事务的特性(ACID)

A--原子性(Atomicity):事务中的操作要么全部成功,要么全部失败。

  • 使用 日志(undo log) 保证异常时可以回滚。

C--一致性(Consistency):事务执行前后,数据库要从一个一致状态,变为另一个一致状态。

  • 依赖原子性 + 隔离性和数据库完整性约束(外键等)共同实现。

I--隔离性(Isolation):多个事务同时执行时,互不干扰。

  • 由隔离级别 + 锁机制 + MVCC实现。

D--持久性(Durability):事务提交后的数据,必须持久保存,即使宕机也不能丢失。

  • 通过redo log保证。

事务并发可能引发的三大问题

脏读(Dirty Read)

  • 定义:一个事务读取到另一个事务未提交的数据,若后者回滚,前者读到的就是 “脏数据”。
  • 本质:读取了未持久化的中间态数据。

不可重复读(Non-repeatable Read)

  • 定义:同一事务内多次读取同一行数据,结果不一致(因其他事务提交了对该数据的修改/删除)。
  • 本质:针对已有数据的更新/删除,导致重复读结果不同。

幻读(Phantom Read)

  • 定义:同一事务两次查询记录数不同(因为别的事务插入了新记录)。
  • 本质:针对新数据的插入/删除,导致范围查询 “凭空出现 / 消失” 记录。

不可重复读和幻读的区别

  • 不可重复读:关注的是记录内容的变化(如值被修改)
  • 幻读:关注的是记录的增删导致的数量变化

事务的四种隔离级别(从低到高)

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED(读未提交) ✔ 会发生 ✔ 会发生 ✔ 会发生
READ COMMITTED(读已提交) ✘ 不会 ✔ 会 ✔ 会
REPEATABLE READ(可重复读)(MySQL 默认) ✘ 不会 ✘ 不会 ⚠ 理论发生,但 MySQL 用 MVCC + 间隙锁 防止
SERIALIZABLE(串行化) ✘ 不会 ✘ 不会 ✘ 不会

隔离级别详细说明

  1. 读未提交(Read Uncommitted)
  • 可以读到未提交数据 → 脏读
  • 最低级别,不会使用 MVCC 快照
  • 不安全,很少实际使用
  • 实现:无锁机制,直接读取最新数据(包括未提交的)。
  • 适用范围:基本不用。

  1. READ COMMITTED(读已提交)
  • 每次读取,都会生成新快照(Oracle 采用)
  • 解决脏读
  • 会发生不可重复读、幻读
  • 实现:基于MVCC,每次查询生成新的一致性快照(快照读);写操作加行锁(当前读)。
  • 适用性:对一致性要求不高的系统。

  1. REPEATABLE READ(可重复读)—— MySQL InnoDB 的默认隔离级别
  • 同一事务内,多次读取使用同一快照(MVCC)
  • 解决:脏读 + 不可重复读
  • MySQL 通过以下手段解决幻读:
    • MVCC解决 读幻读
    • 间隙锁(Gap Lock)解决 写幻读
  • 适用:大多数业务场景。

  1. SERIALIZABLE(串行化)
  • 最严格,事务按顺序执行
  • 使用锁阻止一切并发读写
  • 性能最低
  • 适用:银行转账、订单强一致性场景,但实际仍少用。

补充:

  1. 临健锁(Next-Key Lock):
  • 临键锁 = 行锁(Record Lock) + 间隙锁(Gap Lock)
  • 作用:锁定数据行 + 数据行之间的 “间隙”,防止其他事务插入数据,从而解决幻读(仅可重复读/串行化级别生效)。
    也就是说:它锁住的是 “当前行 + 左侧间隙”
  • 例子:SELECT * FROM account WHERE id > 10 FOR UPDATE 会锁定 id>10 的行,同时锁定 id=10 到下一个存在id的间隙,阻止插入id=11的记录。
  1. 间隙锁(Next-Key Lock):
  • 间隙锁 = 锁住“记录之间的范围(间隙)”的锁;它不锁住已有的数据行,只锁 “空的区间”。
  • 目的是阻止其他事务在该间隙里插入新记录 → 防止幻读。
  1. 隔离级别设置:
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置全局隔离级别(需重启会话生效)
SET GLOBAL transaction_isolation = 'REPEATABLE-READ';

-- 设置会话隔离级别(当前会话生效)
SET SESSION transaction_isolation = 'READ-COMMITTED';
  1. MySQL选择可重复读隔离级别的目的:
  • MySQL选择可重复读隔离级别的主要目的是防止在主从复制过程中数据不一致的现象。通过引入间隙锁和临健锁,确保事务按预期顺序提交和记录在binlog中。
  1. 三者对比
锁类型 锁住内容 目的
行锁(Record Lock) 具体一行记录 不允许其他事务修改该行
间隙锁(Gap Lock) 行与行之间的空隙 阻止其他事务插入新记录
临键锁(Next-Key Lock) 行锁 + 左侧间隙 同时防止插入与修改,防止幻读
posted @ 2025-12-08 20:17  我会替风去  阅读(1)  评论(0)    收藏  举报