事务拿锁时别的请求会礼貌等待
等待锁可能是正常协调,也可能让连接和请求持续排队。PostgreSQL 的 lock_timeout 可以让调用方停止等待,但它不会解释持锁者为什么慢,更不会自动决定业务是否可以重试。应从操作能够接受的延迟出发设定预算,同时找到实际阻塞者;单纯延长超时或增加尝试次数,可能只是扩大同一条等待队列。 坏掉的样子 锁超时分别作用于每一次锁获取尝试,包括语句隐式申请的锁。它测量的是等待当前锁的时间,而不是整条语句的总运行时间。查询已经执行了一段时间,随后又申请一把锁,仍然可能触发这个限制。反过来,多次较短的等待也可能累计超过一个配置间隔。把锁超时理解成“只有语句刚开始时检查一次”,或把它当成整次查询的总截止时间,都会漏掉真实的等待范围。 statement_timeout 限制整条语句执行,其中也包括等锁。如果它更短,可能先于锁超时取消语句。空闲事务会话超时处理的则是另一种状态:事务还开着,但服务器正在等待客户端发下一条命令。卡在更新内部等待锁的后端通常仍是活动状态,等待事件属于锁;不能看到连接排队,就直接把所有等待者叫作空闲事务。真正闲着不提交的持锁者和正在等待的受阻者,需要分别定位。 PostgreSQL 十八还提供事务超时,事务持续过久时会终止整个会话。这与锁超时仅取消语句的失败边界不同,连接池必须丢弃已经断开的连接。两种设置都不是跨多次尝试的应用总截止时间;事务开始前的排队,以及重试退避期间的耗时,仍应计入调用方预算。不要把一个数据库内计时器当成完整请求的时间保证。 配置超时与 SQLSTATE 说明作用范围;先回滚再重试。配置毫秒数不是测得的客户端延迟。 快速验证 准备同一个 PostgreSQL 18 可丢弃数据库,开启甲、乙两个全新的 psql -X -v ON_ERROR_STOP=1 会话。使用同一角色并具备创建模式权限,确认 timeout_demo 尚不存在,显式事务外保持自动提交。实验使用默认的零值锁超时,且没有其他会提前干预的超时设置。下面的毫秒参数只用于快速复现,不是生产建议值。甲先建立独立模式和计数表: CREATE SCHEMA timeout_demo; CREATE TABLE timeout_demo.counter (id integer PRIMARY KEY,n integer); INSERT INTO timeout_demo.counter VALUES (1,0); 甲在显式事务中把数字改成十,暂时不提交,也不回滚,以便继续持有目标行的锁: ...