事务与 MVCC
ACID、隔离级别、与 MySQL InnoDB 对比。
事务与 MVCC
这一课你将能做到
- 用
BEGIN/COMMIT/ROLLBACK包住多步更新,并演示一次回滚 - 说出 PG 默认隔离级别 Read Committed 与 MySQL InnoDB 默认 Repeatable Read 的差异直觉
- 用两会话实验理解「写等待」与 MVCC「读不挡写」的基本图像
为什么要学
转账、改库存、发布课时状态——多语句必须成功一起提交或一起失败。PostgreSQL 用 MVCC(多版本并发控制)实现事务:读通常不阻塞写,写冲突用行锁或更高隔离级别处理。
你在 sql-transaction 已学 ACID;本课对齐官方 Transaction Isolation 与 MVCC 概念,并为 Spring @Transactional 换库时的默认隔离差异打预防针。
先建立图像
会话 A 会话 B
BEGIN BEGIN
UPDATE 行 X … SELECT 行 X → 读到已提交旧版(RC 下按语句快照)
(未提交) UPDATE 行 X → 等待 A 的行锁
COMMIT (A 提交后)B 继续 / 或按隔离级别失败
| 级别 | PostgreSQL 要点 |
|---|---|
| Read Committed(默认) | 每条语句看到语句开始时已提交数据 |
| Repeatable Read | 事务内重复读更一致;可有序列化异常需重试 |
| Serializable | 更强;冲突时 serialization_failure |
MySQL InnoDB 默认常是 Repeatable Read;不要假设两库默认相同。
跟着做
步骤 1:确认 autocommit 习惯
docker exec -it pg-dev psql -U codeforge -d codeforge_pg
-- 单条默认立即提交
UPDATE app.cf_track SET sort_order = sort_order
WHERE slug = 'sql-essentials';
psql 默认自动提交。显式事务必须 BEGIN。
步骤 2:一次可回滚的事务
BEGIN;
UPDATE app.cf_track
SET sort_order = sort_order + 100
WHERE category = 'language';
SELECT slug, sort_order FROM app.cf_track WHERE category = 'language';
ROLLBACK; -- 撤销本事务全部更改
SELECT slug, sort_order FROM app.cf_track WHERE category = 'language';
第二次 SELECT 应回到原值。再练一次 COMMIT 留下变更(可自行加回)。
步骤 3:查看与设置隔离级别
SHOW transaction_isolation;
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT COUNT(*) FROM app.cf_track;
-- 保持事务打开,另开会话插入一行后再在本会话 SELECT COUNT
-- RC:可能看到新行;RR:通常仍是事务开始时的快照行数
COMMIT;