PostgreSQL 中 MVCC 的实践指南
一 核心原理与关键概念
二 典型并发场景与 SQL 实践
BEGIN;
SELECT balance FROM account WHERE id = 1; -- 假设返回 100
-- 其他事务在此期间 UPDATE 并提交为 200
SELECT balance FROM account WHERE id = 1; -- 现在返回 200
COMMIT;
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM my_table WHERE id = 1; -- 假设 xmin=100
-- 其他事务 UPDATE 并提交(新版本 xmin=200)
SELECT * FROM my_table WHERE id = 1; -- 仍看到 xmin=100 的旧版本
COMMIT;
BEGIN;
SELECT id FROM account WHERE user_id = 1 FOR UPDATE;
UPDATE account SET balance = balance - 100 WHERE user_id = 1 AND balance >= 100;
COMMIT;
for {
err := db.Transaction(func(tx *gorm.DB) error {
var acc Account
tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Where("user_id = ?", uid).First(&acc)
if acc.Balance < 100 { return errors.New("insufficient") }
return tx.Model(&acc).Update("balance", acc.Balance-100).Error
})
if err == nil { break }
if pgErr, ok := err.(pgdriver.Error); ok && pgErr.Code == "40001" {
continue // 重试
}
return err
}
实践要点:优先使用READ COMMITTED;需要一致性读时用REPEATABLE READ;仅在强一致且冲突可控时用SERIALIZABLE;用显式锁替代盲目提升隔离级别。三 维护与观测要点
VACUUM [FULL] [ANALYZE] [VERBOSE] table_name;
建议保持autovacuum = on,并根据负载调整阈值与成本参数。-- 查看死元组
SELECT schemaname, relname, n_dead_tup
FROM pg_stat_all_tables
WHERE n_dead_tup > 0;
-- 查看当前事务与快照
SELECT txid_current(), txid_current_snapshot();
-- 监控活动与锁
SELECT * FROM pg_stat_activity;
SELECT * FROM pg_locks;
四 常见误区与优化建议
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。