PostgreSQL并发更新同一行不同字段的行为及事务级别问询
并发更新PostgreSQL同一行不同字段的运行行为
- PostgreSQL的行锁是行粒度的,不支持字段级别的锁,所以即使多个事务修改的是同一行的不同字段,也会竞争同一把行锁。第一个成功获取行锁的事务会先执行更新,其余事务会进入阻塞状态,直到持有锁的事务提交或回滚。
- 若持有锁的事务提交:等待的事务会基于最新提交的行版本执行自己的更新逻辑,因为修改的是不同字段,两个事务的修改不会互相覆盖,最终行数据会保留所有已提交事务的修改结果。举个常见的示例:事务A更新
user表id=1的name字段为"张三",事务B同时更新同一条记录的age字段为25,最终这条记录的name和age都会修改成功。 - 若持有锁的事务回滚:等待的事务会直接基于锁释放后的行版本执行更新,不受回滚事务的影响。
- 如果当前事务隔离级别是可重复读及以上,且等待锁的事务在进入阻塞前已经读取过该行的旧版本,那么锁释放后如果发现行版本已经被其他事务修改,会抛出
could not serialize access due to concurrent update错误,需要应用层手动重试事务。
该场景下的事务隔离级别
- PostgreSQL的事务隔离级别是全局/会话/事务级别的配置,不会随操作场景自动切换,默认的隔离级别为读已提交(Read Committed)。
- 你可以根据业务需求手动调整隔离级别:比如执行
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;可以将当前事务的隔离级别调整为可重复读。 - 读已提交级别下,上述并发更新不同字段的场景几乎不会有冲突报错,只要按顺序拿到行锁就能正常提交,是最适合这类高并发更新场景的隔离级别。
内容的提问来源于stack exchange,提问作者IRCodder
相关产品推荐
相关产品推荐

