PostgreSQL 14可序列化事务无逻辑冲突却报错问题咨询
PostgreSQL 14可序列化隔离级别下的并发更新冲突解析
问题场景
创建测试表:
create table users ( id serial primary key, first_name varchar(255) not null, last_name varchar(255) not null ); insert into users(first_name, last_name) values ('a', 'a');
两个并发的SERIALIZABLE隔离级别事务分别执行UPDATE:
事务1:
begin isolation level serializable; update users set first_name = 'aa' where first_name = 'a'; commit;
事务2(并发执行):
begin isolation level serializable; update users set last_name = 'aa' where last_name = 'a'; commit;
实际执行时,后启动的事务会先等待前一个事务提交,随后抛出并发错误。但从逻辑上看,两个事务按任意顺序执行结果一致,似乎不违反可序列化规则,为何会出现冲突?是否是整行锁导致的机制泄漏?
原因解析
行锁引发的等待行为
PostgreSQL中,UPDATE操作会对匹配到的行施加排他行锁。第一个事务执行UPDATE时,会锁定目标行;第二个事务的UPDATE同样需要锁定同一行,因此会进入等待状态,直到第一个事务提交释放锁。SSI的保守冲突判定逻辑
PostgreSQL的SERIALIZABLE隔离级别基于可序列化快照隔离(SSI)实现,核心是检测可能破坏序列化语义的冲突场景。虽然两个事务修改的是不同字段,但它们都对同一行执行了写入操作,属于SSI定义的写-写冲突范畴。
SSI的设计优先保证序列化安全性,而非极致并发度。它无法精准判定“修改不同字段”这种场景绝对不会破坏序列化语义,因此采取保守策略:只要两个事务都修改了同一行,无论字段是否重叠,都会判定为序列化冲突,触发事务回滚,彻底避免潜在的异常风险。
- 并非整行锁的机制泄漏
这不是机制泄漏,而是设计取舍的结果。整行锁是UPDATE操作的固有行为——PostgreSQL采用tuple级行存储,修改任何字段都需要生成新tuple并锁定原tuple;而SSI的冲突判定逻辑为了确保序列化语义的严格性,选择牺牲部分非关键场景的并发能力,换取整体数据一致性的绝对保障。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

