百科 / 错误代码 / Class 55 前置状态不满足
55P03 lock_not_available
ERROR 已实测 详解 实测通过
- 条件名
lock_not_available- 宏名称
ERRCODE_LOCK_NOT_AVAILABLE- 启用版本
- 8.0
- 状态
- 活跃
版本覆盖
速览
55P03 表示在当前等待策略下无法取得请求的锁。固定路径覆盖行锁、关系锁、LOCK TABLE、lock_timeout,以及无法取得关系锁时跳过对象的维护命令。
含义
行锁调用使用 LockWaitError 和 ConditionalXactLockTableWait()/ConditionalMultiXactIdWait(),立即报告 could not obtain lock on row in relation "%s"。关系锁和 LOCK TABLE 使用 ConditionalLockRelationOid(),报告关系对象变体。lock_timeout 是另一个 ERROR 路径,报 canceling statement due to lock timeout;它表示等待超过配置的 timeout,并不表示请求使用了 NOWAIT。
VACUUM 和 ANALYZE 取得关系锁失败时也使用此 SQLSTATE,但它们的 ereport(elevel) 有意不提升为 ERROR:普通维护报告 WARNING,autovacuum 的 verbose 路径可能使用 LOG。命令会跳过该对象并继续,因此这类 warning 不等于事务已中止。
报文模板
源码里的格式串,不是某一次运行的输出。%s 之类是占位符,实际报文会填入对象名与取值。适用范围一栏是核验时留下的原始英文记录,未经翻译。
could not obtain lock on row in relation "%s"
could not obtain lock on relation "%s.%s"
canceling statement due to lock timeout
could not obtain lock on relation "%s"
skipping vacuum of "%s" --- lock not available
skipping analyze of "%s" --- lock not available
诊断
保留完整 primary message、severity、关系或行名、锁模式和语句。检查 pg_stat_activity、pg_locks、阻塞 PID、事务时长,以及语句使用的是 NOWAIT、lock_timeout 还是维护命令。不要把 VACUUM/ANALYZE 跳过对象的 warning 当成 DML 失败。
已接受的行锁案例使用独立 blocker 和 autocommit contender。显式事务中的锁 ERROR 会使 session 进入 INERROR,直到 ROLLBACK 或 ROLLBACK TO SAVEPOINT;该案例的 autocommit contender 在失败后保持 IDLE。
处理
协调或释放 blocker,或明确选择等待、timeout、skip 策略。显式事务中的 ERROR 后,先回滚整个事务或回到既有 savepoint,再发送 SQL,并核对已提交工作后重放。autocommit 下先改变阻塞或 timeout 条件,再按幂等规则重试语句。维护 WARNING/LOG 只需记录跳过的关系并稍后补做维护;命令没有中止事务时不要执行 ROLLBACK。
可复现案例
在一次性实例上执行过的场景。其中 1 个附有可执行 SQL,正文相应小节里给出。
nowait_row_lock PG 10 / 18 有 SQL
前置条件
- Two runner-owned sessions target one row.
- The blocker acquires its lock before the NOWAIT statement is sent.
触发
Hold a row lock in one explicit transaction, issue SELECT FOR UPDATE NOWAIT from a second session, then release and retry.
断言
- SQLSTATE is 55P03 with ERROR severity
- The diagnostic identifies a row lock that cannot be obtained immediately
- The blocker is INTRANS and the NOWAIT contender remains IDLE after its error
- After blocker rollback the same contender updates and reads the row
处置
Use a bounded NOWAIT failure as a signal, release or resolve the blocker, then retry according to the application’s lock policy; this case does not treat sleeping as synchronization.
清理
Close all runner connections and drop the case schema with an owner connection.
实测诊断
选定注册表创建 blocker,在显式事务中持有 SELECT ... FOR UPDATE,并由 autocommit contender 发出 FOR UPDATE NOWAIT。PostgreSQL 18.6 与 10.21 均返回 ERROR / 55P03 及 could not obtain lock on row in relation "nowait_rows";contender 保持 IDLE。blocker 回滚后,同一 contender 将 marker 更新为 repaired 并完成验证。
代表案例
以下 SQL 是带角色说明的注册表片段。setup 只执行一次,blocker 与 contender 必须使用不同会话;片段只覆盖行锁 NOWAIT,不覆盖 lock_timeout 或维护跳过分支。
-- setup(一个维护会话)
CREATE TABLE nowait_rows(id integer PRIMARY KEY, marker text NOT NULL);
INSERT INTO nowait_rows VALUES (1, 'seed');
-- blocker 会话:保持事务打开
BEGIN;
SELECT id FROM nowait_rows WHERE id = 1 FOR UPDATE;
-- contender 会话,开启 autocommit:这里触发 55P03
SELECT id FROM nowait_rows WHERE id = 1 FOR UPDATE NOWAIT;
-- blocker 会话
ROLLBACK;
-- 释放 blocker 后,在 contender 会话中修复并验证
UPDATE nowait_rows SET marker = 'repaired' WHERE id = 1 RETURNING marker;
SELECT marker FROM nowait_rows WHERE id = 1;
该案例只确认行锁机制、ERROR/IDLE 边界和修复步骤,不能据此断言每种锁模式或维护命令有相同 severity。
版本
锁定目录从 8.0.0 记录此条件;固定源码覆盖 PostgreSQL 18.6。已接受的运行观察来自 PostgreSQL 18.6 和 10.21。
来源
- 上游源码 src/backend/utils/errcodes.txt 第 427 行
- 上游源码 src/backend/access/heap/heapam.c 第 5178 行
- 上游源码 src/backend/catalog/namespace.c 第 585 行
- 上游源码 src/backend/tcop/postgres.c 第 3420 行
- 上游源码 src/backend/commands/lockcmds.c 第 130 行
- 上游源码 src/backend/commands/vacuum.c 第 835 行
- 核验材料 verify/cases/55P03/cases.json
- 核验材料 verify/results/ops-55p03-latest-1/latest/raw.jsonl
- 核验材料 verify/results/ops-55p03-pg10-1/pg10/raw.jsonl
- 核验材料 verify/results/ops-55p03-latest-1/latest/summary.json
- 核验材料 verify/results/ops-55p03-pg10-1/pg10/summary.json
- 核验材料 verify/cases/55P03/snippets.json
证据
断言
每条断言都写明了是怎么核实的,以及它不覆盖什么。这一层是核验时留下的原始英文记录,照原样呈现,未经翻译。
-
55P03 is lock_not_available in SQLSTATE Class 55.
-
The fixed row-lock, relation-lock, LOCK TABLE, lock_timeout, and maintenance paths support the concrete mechanisms and messages described.
-
VACUUM/ANALYZE emits this SQLSTATE at WARNING for normal maintenance or LOG for verbose autovacuum, while lock and timeout paths use ERROR.
-
The locked catalogue records 55P03 from 8.0.0; that boundary does not prove exact implementation introduction.
-
The nowait_row_lock case passed on PostgreSQL 18.6 and 10.21 with SQLSTATE, severity or disconnect outcome, recovery/repair, cleanup, and isolated-target stop assertions.
运行记录
| 目标 | 服务器版本 | 结果 | 覆盖案例 |
|---|---|---|---|
| latest | 18.6 (Homebrew) | passed | nowait_row_lock |
| pg10 | 10.21 (Debian 10.21-1.pgdg90+1) | passed | nowait_row_lock |
同类错误代码
Class 55 前置状态不满足 下的其他成员。