百科 / SQL 状态码 / Class 55 对象未处于所需状态
55P03 lock_not_available
55P03 — lock_not_available
ERROR 已实测 详解 实测通过
- 条件名
lock_not_available- 宏名称
ERRCODE_LOCK_NOT_AVAILABLE- 最早已知存在
- 8.0.0
- 状态
- 有效
手册收录:8.1、8.2、8.3、8.4、9.0、9.1、9.2、9.3、9.4、9.5、9.6、10、11、12、13、14、15、16、17、18、19、20。此处仅表示同版本手册收录,运行证据仍以原核验构建为准。
版本覆盖
版本条依据已采样构建显示;灰色版本可能尚未采样,悬停可查看。手册链接随版本选择,源码和运行证据保持原核验构建。
55P03
速览 {#at-a-glance}
55P03 表示在当前等待策略下无法取得请求的锁。固定路径覆盖行锁、关系锁、LOCK TABLE、lock_timeout,以及无法取得关系锁时跳过对象的维护命令。
含义 {#meaning}
行锁调用使用 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 不等于事务已中止。
诊断 {#diagnosis}
保留完整 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。
处理 {#response}
协调或释放 blocker,或明确选择等待、timeout、skip 策略。显式事务中的 ERROR 后,先回滚整个事务或回到既有 savepoint,再发送 SQL,并核对已提交工作后重放。autocommit 下先改变阻塞或 timeout 条件,再按幂等规则重试语句。维护 WARNING/LOG 只需记录跳过的关系并稍后补做维护;命令没有中止事务时不要执行 ROLLBACK。
实测诊断 {#observed-diagnostics}
选定注册表创建 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 并完成验证。
代表案例 {#case}
以下 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。
版本 {#versions}
锁定目录从 8.0.0 记录此条件;固定源码覆盖 PostgreSQL 18.6。已接受的运行观察来自 PostgreSQL 18.6 和 10.21。
相关 {#related}
来源 {#sources}
src/backend/access/heap/heapam.c#L5178-5210
src/backend/catalog/namespace.c#L585-610
src/backend/tcop/postgres.c#L3420-3444
src/backend/commands/lockcmds.c#L130-145
src/backend/commands/vacuum.c#L835-880
结构化证据记录保存固定消息角色、维护 severity 以及已接受的运行产物。
来源
- 上游源码 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 |
报文模板
源码里的格式串,不是某一次运行的输出。%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
可复现案例
在一次性实例上执行过的场景。其中 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.
同类 SQL 状态码
| 状态码 | 条件名 | 宏名称 | 严重等级 | 版本 |
|---|---|---|---|---|
| 55000 | object_not_in_prerequisite_state | ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE |
ERROR | 7.4 起已知 |
| 对象或服务器未处于操作所需的前置状态。 | 有效 | |||
| 55006 | object_in_use | ERRCODE_OBJECT_IN_USE |
ERROR | 7.4 起已知 |
| 对象正被使用,操作与进行中的占用冲突。 | 有效 | |||
| 55P02 | cant_change_runtime_param | ERRCODE_CANT_CHANGE_RUNTIME_PARAM |
ERROR | 7.4 起已知 |
| 当前上下文或阶段不允许修改该运行时参数。 | 有效 | |||
| 55P03 | lock_not_available | ERRCODE_LOCK_NOT_AVAILABLE |
ERROR | 8.0.0 起已知 |
| 当前等待策略下取不到锁,含 lock_timeout 到期。 | 有效 | |||
| 55P04 | unsafe_new_enum_value_usage | ERRCODE_UNSAFE_NEW_ENUM_VALUE_USAGE |
ERROR | 12.0 起已知 |
| 同一事务中使用了尚未提交的新增 enum 值。 | 有效 | |||