PostgreSQL可重复读级别下SKIP LOCKED触发序列化错误排查
PostgreSQL可重复读隔离级别下SKIP LOCKED仍报序列化访问错误的原因
场景复现
- 事务1(可重复读隔离级别)执行带SKIP LOCKED的行锁查询:
select * from booker.review_tasks where review_task_id in ( 2140285001, 2140285031, 2140304551 ) for update skip locked;
- 并发事务2对同表ID匹配的行执行更新:
update booker.review_tasks set priority = 190 where review_task_id in ( 2140285001, 2140304551 );
- 事务1抛出错误:
was aborted: ERROR: could not serialize access due to concurrent update Call getNextException to see other errors in the batch. at com.amazon.contentreviewplatformservice.db.RWNamedJdbcTemplate.batchUpdate(RWNamedJdbcTemplate.java:126) ~[ContentReviewPlatformService-1.0.jar:?] at com.amazon.contentreviewplatformservice.db.dao.DAOUtils.changeUserTaskAssignmentStatus(DAOUtils.java:126) ~[ContentReviewPlatformService-1.0.jar:?] at com.amazon.contentreviewplatformservice.workflow.dao.WorkflowManagerDAO.changeReviewState(WorkflowManagerDAO.java:784) ~[ContentReviewPlatformService-1.0.jar:?]
核心原因
对SKIP LOCKED的作用边界、PostgreSQL可重复读(RR)隔离级别的规则存在两个常见认知偏差:
- SKIP LOCKED的作用范围有严格限制
SKIP LOCKED只会跳过「执行加锁动作的瞬间,被其他未提交事务持锁的行」,它的执行逻辑顺序是:
- 第一步:基于当前事务的一致性快照,扫描匹配WHERE条件的行版本
- 第二步:逐行尝试对最新版本的行加FOR UPDATE锁
- 第三步:如果加锁时发现行已被其他未提交事务锁定,直接跳过该行;如果加锁成功就返回该行
它不会处理「行在事务快照生成后,已经被其他事务修改并提交」的场景,这类场景的处理优先级远高于SKIP LOCKED逻辑。
- 可重复读隔离级别下的行版本冲突会直接触发序列化错误
可重复读隔离级别的核心要求是:事务整个生命周期内看到的数据,和事务启动时创建的一致性快照完全一致。当事务1扫描到目标行、尝试加锁时,如果发现该行已经被其他并发事务修改并提交(即行的最新版本和快照里的版本不一致),PostgreSQL不会绕过一致性要求去给旧版本行加锁,也不会自动读取最新版本的行,会直接抛出could not serialize access due to concurrent update错误,这个流程根本不会走到SKIP LOCKED的判断逻辑。
关于「已被锁定的行为何能被其他事务并发更新」的说明
假设的「事务1先锁行、事务2再更新」的执行时序完全不成立:事务1根本没有先拿到那两行的锁。真实的并发时序大概率是:
- 事务1启动,生成可重复读级别的一致性快照,但还没扫描到目标ID的行,自然没有加任何锁
- 事务2启动,率先拿到2140285001、2140304551两行的行锁,执行更新后直接提交,释放锁
- 事务1此时才扫描到这两行,尝试加锁时检测到行版本和自己的快照不一致,直接抛出序列化错误
在事务1成功给行加上锁之前,其他事务完全可以正常对行执行更新、加锁操作,SKIP LOCKED没有任何提前占锁的能力。
规避方案
如果需要SKIP LOCKED正常跳过被锁行、不抛出序列化错误,有两种可选方案:
- 将事务隔离级别调整为读提交(RC):该级别下碰到行版本更新时,会自动读取最新提交的行版本,重新匹配WHERE条件后再加锁,碰到仍被未提交事务锁定的行才会触发SKIP LOCKED逻辑跳过
- 调整业务逻辑,保证
SELECT ... FOR UPDATE SKIP LOCKED语句在事务启动后第一时间执行,减少和其他更新事务的冲突窗口
内容的提问来源于stack exchange,提问作者Jeffin Sam
相关产品推荐
相关产品推荐

