Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

PostgreSQL 事务

内容涵盖:事务基础、隔离级别、锁、常见问题、最佳实践、性能建议、异常处理。

1. 什么是事务(Transaction)?

事务(Transaction)是数据库中的 原子操作单元,具有:

  1. 原子性(Atomicity)
  2. 一致性(Consistency)
  3. 隔离性(Isolation)
  4. 持久性(Durability)

简称 ACID

事务确保一组 SQL 要么全部成功,要么全部失败,不会出现部分成功的情况。

2. PostgreSQL 如何开启 / 提交 / 回滚事务?

自动事务模式(默认)

每条 SQL 都是一个独立事务:

INSERT INTO ... ;   -- 自动开始 + 自动提交

手动事务模式(推荐)

BEGIN;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;   -- 成功

失败回滚:

ROLLBACK;

等价命令:

BEGIN 或 START TRANSACTION
COMMIT
ROLLBACK

3. PostgreSQL 事务隔离级别(Isolation Levels)

PostgreSQL 支持 4 种隔离级别:

隔离级别 说明 PostgreSQL 默认
READ UNCOMMITTED 允许读未提交(脏读)。PostgreSQL 实际等同于 READ COMMITTED,不支持真正的脏读
READ COMMITTED 每条语句看到提交后的最新数据 ✅ 默认
REPEATABLE READ 整个事务期间看到一致的快照 ✅ 不可重复读不存在
SERIALIZABLE 完全串行化 ✅ 最强

设置隔离级别:

BEGIN ISOLATION LEVEL REPEATABLE READ;

或:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

4. PostgreSQL 中事务快照(MVCC)

PostgreSQL 使用 MVCC(多版本并发控制) 来保证事务隔离:

  • 修改不会阻塞读
  • 读也不会阻塞写
  • 每个事务看到的是自己快照内的数据

这使得 PostgreSQL 非常适合集群 OLTP 高并发场景。

5. 事务 + 锁关系(必会)

常见锁:

锁类型 触发场景
Row Share SELECT FOR SHARE
Row Exclusive INSERT、UPDATE、DELETE
Share CREATE INDEX
Exclusive DROP TABLE
Access Exclusive ALTER TABLE、VACUUM FULL

行级锁(最常用)

SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

6. Postgres 事务的常见问题

❗1. 死锁(Deadlock)

ERROR: deadlock detected

常见原因:

  • 两个事务互相等待对方的行锁
  • 非全局一致的锁顺序

💡 解决办法:保持一致的锁顺序

❗2. 事务太长导致膨胀(bloat)

长事务无法释放旧版本记录 -> 表膨胀 -> 性能下降。

解决:

  • 避免长事务
  • 避免长时间保持闲置事务
  • 监控 pg_stat_activity

❗3. idle in transaction

该状态会造成:

  • 行无法删除(VACUUM 无法清理)
  • 表膨胀、查询变慢

避免:

  • 每个事务必须显式 COMMIT 或 ROLLBACK
  • 应用一定要正确关闭连接

7. 常见事务模式

① 单条语句事务(默认)

最简单,但连续操作不安全。

② 手动事务

推荐用于一组逻辑性的更新。

③ SAVEPOINT(子事务)

用于捕获局部异常,而不回滚整个事务。

BEGIN;

SAVEPOINT sp1;

INSERT INTO table VALUES (...);

ROLLBACK TO sp1;

COMMIT;

8. PostgreSQL 高级事务语法

① SELECT … FOR UPDATE

锁行用于安全读取:

SELECT * FROM orders WHERE id = 10 FOR UPDATE;

② SELECT … FOR NO KEY UPDATE / SHARE / KEY SHARE

PostgreSQL 细化了读写锁:

语法 锁级别 场景
FOR UPDATE 强写锁 准备修改该行
FOR NO KEY UPDATE 不修改主键时使用 更轻量
FOR SHARE 共享锁 不影响别人读
FOR KEY SHARE 最弱 外键检查

9. PostgreSQL 事务在 Python SQLAlchemy 中使用

自动事务(2.0 API)

async with async_session() as session:
    async with session.begin():
        obj = MyTable(...)
        session.add(obj)

手动 commit / rollback

session = Session()

try:
    session.add(obj)
    session.commit()
except:
    session.rollback()
    raise

10. 最佳实践总结(非常重要)

避免长事务

保持事务尽可能短。

不要让事务 idle

否则会导致 MVCC 膨胀。

确保应用出现异常时自动 rollback

大事务拆小事务

减少锁冲突。

用 FOR UPDATE 保证数据一致性

用于扣款、库存等业务场景。

隔离级别用默认即可

READ COMMITTED 足够多数业务。

11. 常见事务排查 SQL

查看正在运行的事务:

SELECT * FROM pg_stat_activity WHERE state = 'active';

查看锁:

SELECT * FROM pg_locks l JOIN pg_stat_activity a 
    ON l.pid = a.pid;

查看死锁:

SELECT * FROM pg_stat_activity WHERE wait_event = 'Deadlock';

12. 事务调优建议

  • 使用 statement_timeout
  • 避免大量 UPDATE,改用 UPSERT 或 INSERT-only 模式
  • 加索引避免锁冲突
  • 高并发下使用 SKIP LOCKED

例如:

SELECT * FROM jobs
WHERE status = 'pending'
FOR UPDATE SKIP LOCKED
LIMIT 1;

📌 总结

PostgreSQL 事务体系非常强大(MVCC 超越大多数数据库),理解它可以解决:

  • 并发写冲突
  • 死锁
  • 锁表问题
  • 膨胀问题
  • 一致性保证