标准答案

  1. 先查看 pg_stat_activity 的 xact_start、query_start、state、wait_event、usename、application_name 和 backend_xid,区分仍在执行、锁等待、idle in transaction 和连接池空闲。
  2. 长事务会让数据库不能确认某些旧版本已经不再需要,可能使 autovacuum 清理受阻,进而出现 dead tuples、表膨胀、磁盘增长和查询变慢。
  3. 事务内不应等待外部 HTTP、用户输入、长时间重试或无限队列;应把外部动作移到事务外,并用状态记录或 Outbox 表表达业务进度。
  4. 可以按场景配置 statement_timeout 和 idle_in_transaction_session_timeout,但超时后应用必须回滚事务、关闭或重置连接,不能把污染状态的连接放回连接池。
  5. 终止会话前要判断它是否正在提交、执行大批量修复或持有关键锁,评估回滚成本后再止血,并从连接归还和异常处理代码上修复根因。

题目解析

数据库看到的“连接空闲”和“事务结束”是两件事。客户端可能已经停止发送 SQL,但事务仍然打开,快照和锁的生命周期并没有结束。

长事务常与连接池、异常路径和业务代码混合出现:请求超时后连接没有 rollback,或者代码在事务中调用慢下游,都会让数据库长时间保留资源。

治理时应先采集会话和锁证据,再对异常会话做有边界的终止;仅仅增加连接数或频繁 kill,会把资源泄漏和数据回滚成本转移成更大的故障。

常见误区

  • 误区:只看 CPU 和 active query。改正:idle in transaction 也可能持有快照和锁,应查看事务开始时间与会话状态。
  • 误区:看到长事务就批量终止所有连接。改正:先识别业务影响和回滚成本,优先摘除异常实例并修复事务生命周期。
  • 误区:把数据库超时当作事务自动清理。改正:客户端收到取消后仍要确认 rollback 和连接重置,否则连接池会复用不干净的会话状态。

作者信息