You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL使用Serializable隔离级别未触发并发插入冲突错误排查

问题分析与解决方案

为什么Serializable隔离级别未触发冲突?

PostgreSQL的Serializable隔离级别核心是确保事务执行结果等价于某一种串行执行顺序。在你的场景中:

  • 若串行顺序为「T1先执行,T2后执行」:T1计算acc=2620的sum(amt)为110,插入user_id=-1、acc=2630、amt=110的行;随后T2插入user_id=737、acc=2620、amt=100的行。这个结果和你并发执行的实际结果完全一致。
  • 由于存在合法的串行执行顺序匹配并发结果,Serializable不会判定为冲突,因此不会触发回滚。

实现需求的可行方案

要达成「基于指定acc的现有数据插入新行时,若存在针对该acc的并发插入则回滚T1」的目标,你需要显式锁定acc=2620的数据集,阻止其他事务插入同acc的新行,以下是两种常用方案:

1. 利用间隙锁阻止新行插入(推荐,并发影响较小)

前提是acc列已创建B-tree索引,然后在T1中先执行带锁的查询:

begin;
set transaction isolation level serializable;

-- 锁定acc=2620的索引范围,阻止插入新的同acc行
select sum(amt) from account where acc >= 2620 and acc <= 2620 for update;

insert into account (user_id, acc, amt) 
values (-1, 2630, (select sum(sub.amt) from account sub where sub.acc = 2620));

commit;

这里的范围查询会触发PostgreSQL的间隙锁,覆盖acc=2620对应的索引区间,其他事务插入acc=2620的行时会被阻塞,直到T1提交或回滚;若T2先执行插入,T1的锁查询会等待,最终根据提交顺序决定是否触发冲突。

2. 使用表级锁(简单但并发性能低)

若业务并发量较低,可直接对表加锁阻止所有写操作:

begin;
set transaction isolation level serializable;

-- 阻止其他事务执行INSERT/UPDATE/DELETE
lock table account in share row exclusive mode;

insert into account (user_id, acc, amt) 
values (-1, 2630, (select sum(sub.amt) from account sub where sub.acc = 2620));

commit;

该方式会锁定整个表,所有其他写操作必须等待T1完成,适合并发需求不高的场景。

内容的提问来源于stack exchange,提问作者asdasd-mjeesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:57:54