一、什么是事务隔离级别
在数据库中,**事务隔离级别(Transaction Isolation Level)**用于控制多个事务并发执行时的可见性规则。
SQL 标准定义了四种隔离级别:
| 隔离级别 | 可能出现的问题 |
|---|---|
| Read Uncommitted | 脏读、不可重复读、幻读 |
| Read Committed | 不可重复读、幻读 |
| Repeatable Read | 幻读 |
| Serializable | 无并发问题 |
常见的并发问题:
1️⃣ 脏读(Dirty Read)
读取到另一个事务 未提交的数据
2️⃣ 不可重复读(Non-repeatable Read)
同一事务内两次读取同一行数据结果不同
3️⃣ 幻读(Phantom Read)
同一事务两次查询 返回的行数不同
二、PostgreSQL支持的隔离级别
PostgreSQL同样支持SQL标准的四种隔离级别,但实际实现略有不同。
| 隔离级别 | PG支持情况 | 说明 |
|---|---|---|
| Read Uncommitted | 实际等同于RC | PG不会出现脏读 |
| Read Committed | 默认级别 | 每条SQL看到已提交数据 |
| Repeatable Read | 完整支持 | 使用Snapshot Isolation |
| Serializable | 完整支持 | 使用SSI算法 |
三、Read Committed(默认隔离级别)
PostgreSQL 默认隔离级别是:
READ COMMITTED
特点:
-
每条 SQL 都读取 当前已提交数据
-
不会脏读
-
可能出现不可重复读
-
可能出现幻读
示例
事务A:
BEGIN;
SELECT balance FROM account WHERE id = 1;
事务B:
UPDATE account SET balance = 200 WHERE id = 1;
COMMIT;
事务A再次查询:
SELECT balance FROM account WHERE id = 1;
结果可能变化,这就是 不可重复读。
四、Repeatable Read(可重复读)
在 PostgreSQL 中:
REPEATABLE READ
是基于 Snapshot Isolation(快照隔离) 实现的。
事务开始时会创建一个 数据快照(Snapshot):
事务开始 → 创建 snapshot
之后所有查询都基于这个 snapshot
特点:
-
不脏读
-
不可重复读
-
不会出现幻读
-
不需要锁
示例:
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM orders WHERE price > 100;
即使其他事务插入新数据:
INSERT INTO orders VALUES (...)
当前事务也 看不到新增数据。
这就是 快照隔离。
五、Serializable(可串行化)
Serializable 是 最高隔离级别。
PostgreSQL 使用:
SSI(Serializable Snapshot Isolation)
核心思想:
-
不加锁
-
通过检测冲突保证串行执行效果
如果检测到冲突:
ERROR: could not serialize access due to concurrent update
此时需要 应用层重试事务。
示例:
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
优点:
-
高并发
-
不会出现任何并发问题
六、PostgreSQL与MySQL隔离级别实现差异
虽然 PostgreSQL 和 MySQL 都支持相同的隔离级别名称,但实现方式完全不同。
| 特性 | PostgreSQL | MySQL(InnoDB) |
|---|---|---|
| 默认隔离级别 | Read Committed | Repeatable Read |
| MVCC实现 | tuple version | undo log |
| Repeatable Read | Snapshot Isolation | MVCC + Gap Lock |
| Serializable | SSI | 强制锁 |
| Gap Lock | ❌ | ✅ |
七、MySQL为什么需要Gap Lock
MySQL为了防止幻读,需要:
Gap Lock
Next-Key Lock
例如:
SELECT * FROM user WHERE id > 10 FOR UPDATE;
MySQL会锁:
(10, +∞)
这样其他事务无法插入新记录。
缺点:
-
锁范围大
-
并发性能下降
八、PostgreSQL为什么没有Gap Lock
PostgreSQL使用:
MVCC + Snapshot
事务读取的是:
历史版本
因此不需要锁范围来阻止插入。
优势:
-
并发能力强
-
不会产生大量锁
九、PostgreSQL为什么没有Read Uncommitted
SQL标准允许:
READ UNCOMMITTED
但 PostgreSQL 中:
READ UNCOMMITTED == READ COMMITTED
原因是:
PostgreSQL 的 MVCC 架构 天然不允许读取未提交数据。
所以 PG 永远不会出现脏读。
十、查看和设置隔离级别
查看当前隔离级别
SHOW transaction_isolation;
输出示例:
read committed
设置事务隔离级别
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
或者:
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
十一、总结
PostgreSQL 的事务隔离级别总结如下:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| Read Uncommitted | ❌ | ✔ | ✔ |
| Read Committed | ❌ | ✔ | ✔ |
| Repeatable Read | ❌ | ❌ | ❌ |
| Serializable | ❌ | ❌ | ❌ |
PostgreSQL 的优势:
-
强大的 MVCC机制
-
Repeatable Read 无幻读
-
Serializable 使用SSI并发更高
因此 PostgreSQL 在 高并发系统、金融系统、数据平台中非常受欢迎。