四种隔离级别
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 的核心思想是:
- 每次写操作 不直接覆盖旧数据,而是创建 新版本
- 在事务中多次查询返回结果是同一个版本版本快照
- 支持读写并行,互不干扰,无加锁且不阻塞
- 但 写-写冲突 仍然需要处理。不同数据库处理方式不同:
写-写冲突 不同数据库处理方式:


1293

被折叠的 条评论
为什么被折叠?



