数据库事务隔离级别,以及幻读偏斜问题解决

四种隔离级别

ANSI SQL 标准定义了四种事务隔离,MySQL 对4种都支持

隔离级别 脏读 不可重复读 幻读 说明
读未提交(Read Uncommitted) 存在 存在 存在 允许读其他事务未提交的修改,性能最高但一致性最差(几乎不用)
读已提交(Read Committed) 避免 存在 存在 只能读已提交的数据,Oracle 与 PostgreSQL 默认,但存在重复读问题
可重复读(Repeatable Read) 避免 避免 多数避免 MySQL InnoDB 默认,基于 MVCC 读快照,但存在幻读问题
串行化(Serializable) 避免 避免 避免 事务串行执行,隔离级别最高,并发效率最低,适合减库存,减余额等场景

事务隔离是为解决下面问题:

脏读 - 事务A读取了事务B未提交的数据
不可重复读 - 事务A多次读取同一行数据,因事务B更新而不一致
幻读 - 事务A查询的结果行数,因事务B插入/删除而不一致
串行化异常 - 事务A与事务B同并行写数据时,因先后顺序不同而结果不一致

不同数据库对SQL标准的定义并非完全支持,具体实现也有所区别
PostgreSQL 和 Oracle 都不支持读未提交,并且 Oracle 不支持可重复读
PostgreSQL 和 Oracle 的 Serializable 是基于:MVCC + 提交检测
MySQL 的 Serializable 是基于:行锁,间隙锁


锁定读

解决幻读问题,我们可以使用显式的 锁定读 例如:

SELECT ... FOR UPDATE;  -- 排他锁(X锁)
SELECT ... LOCK IN SHARE MODE;  -- 共享锁(S锁),或 MySQL 8.0+ 支持的写法 FOR SHARE

这样在再执行 SELECT 时就会加锁,或阻塞,并且读取到的数据总是最新版本,而非快照版本。
MySQL(InnoDB 引擎)在 Serializable 隔离级别下,SELECT 语句会自动转换为 SELECT … LOCK IN SHARE MODE


MVCC (多版本并发控制)

锁定读会导致阻塞,MVCC 的诞生就是为实现读写并行,并且保证了重复读的一致性
MVCC 的核心思想是:

  • 每次写操作 不直接覆盖旧数据,而是创建 新版本
  • 在事务中多次查询返回结果是同一个版本版本快照
  • 支持读写并行,互不干扰,无加锁且不阻塞
  • 但 写-写冲突 仍然需要处理。不同数据库处理方式不同:

写-写冲突 不同数据库处理方式:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值