PostgreSQL 连接中如果某个会话通过 BEGIN 开启事务后长时间不执行任何 SQL,也不提交或回滚,就会进入空闲事务状态。该状态会持有事务快照、行锁以及连接资源,给数据库带来连锁影响。要自动终止这类空闲事务,可以使用 idle_in_transaction_session_timeout 参数。本文围绕该参数展开,介绍其原理、配置方法、监控排查以及注意事项。

空闲事务会带来哪些风险
在 PostgreSQL 中,一个会话通过 BEGIN 或驱动隐式开启事务后,如果长时间没有执行任何 SQL 语句,也没有 COMMIT 或 ROLLBACK,就会进入 idle in transaction 状态。这种状态与完全空闲会话不同,它仍然持有当前事务的快照和已经获取的锁资源。只要事务不结束,这些资源就不会释放,带来的影响会逐渐积累。
首先,最直接的问题是锁等待。假设某个事务执行了更新但忘记提交,它持有的行锁会让其他需要访问这些行的会话一直阻塞,轻则响应变慢,重则连接池耗尽。其次,空闲事务持有的快照会影响 VACUUM 清理旧版本元组,导致表膨胀、索引效率下降。最后,大量空闲事务还会占用后端进程和内存,增加系统负担。因此,为这类事务设置自动终止超时机制非常必要。
idle_in_transaction_session_timeout 的配置方式
PostgreSQL 从 9.6 版本开始引入 idle_in_transaction_session_timeout,默认值为 0,表示不启用自动终止。该参数的单位为毫秒,可以在全局、数据库、用户、会话等多个级别设置。推荐的配置方式有两种:持久化写入配置文件,或使用 ALTER SYSTEM 在线修改并重载。
如果希望永久生效,可以在 postgresql.conf 中加入以下内容,然后执行重载:
# 设置事务内空闲超过60秒自动终止 idle_in_transaction_session_timeout = 60000
执行重载可以使用 SELECT pg_reload_conf(); 或者通过命令行发送 SIGHUP 信号。需要注意的是,修改该参数不会影响已经建立的会话,只会对新会话生效。若要对已有会话生效,需要断开重连或者使用 ALTER SYSTEM 配合 pg_reload_conf 后手动终止旧的空闲事务会话。
第二种方式是使用 ALTER SYSTEM,它允许在不直接编辑配置文件的情况下在线修改,并自动写入 postgresql.auto.conf:
ALTER SYSTEM SET idle_in_transaction_session_timeout = '60s'; SELECT pg_reload_conf();
该命令支持带单位的时间字符串,如 60s、2min、1h,可读性更好。全局设置之外,也可以针对特定用户或数据库设置不同超时,例如通过 ALTER ROLE ... SET 或 ALTER DATABASE ... SET。会话级别直接使用 SET idle_in_transaction_session_timeout = '30s'; 可以在测试时临时调整。
如何定位与终止现有空闲事务
即使配置了超时参数,生产环境中仍然可能存在超时之前积累的空闲事务,或者因为参数设置过大而未能及时清理。此时需要通过 pg_stat_activity 视图查询这些会话的详细信息,包括进程号、用户、状态、持续时间以及最后执行的语句。
以下 SQL 可以列出所有处于 idle in transaction 状态的会话,并按照空闲时间从长到短排序:
SELECT pid,
usename,
datname,
state,
now() - state_change AS idle_duration,
query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY idle_duration DESC;
查询结果中的 idle_duration 表示从进入该状态到现在经过的时间。对确认已经不需要继续的会话,可以使用 pg_terminate_backend(pid) 强制终止。例如终止空闲超过 5 分钟的事务会话:
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND now() - state_change > interval '5 minutes';
终止操作会回滚该会话未提交的事务,释放锁和快照。生产环境中建议先确认这些会话是否存在实际业务影响,再执行批量终止。也可以使用 pg_cancel_backend 尝试取消当前查询,但对于空闲事务,它已经不在执行语句,因此 pg_terminate_backend 更直接。
另外,可以定期通过定时任务或监控平台采集 pg_stat_activity 数据,当空闲事务数量或持续时间超过阈值时触发告警,从源头发现应用代码问题。
idle_session_timeout 与 idle_in_transaction_session_timeout 的区别
PostgreSQL 14 新增了 idle_session_timeout,用于自动终止完全空闲的会话,即不处于事务中、也没有执行任何 SQL 的连接。它和 idle_in_transaction_session_timeout 针对的对象不同:后者只处理已经开启事务但未提交且无活动语句的会话,前者处理没有开启事务的闲置连接。
这两个参数可以同时配置。例如将 idle_session_timeout 设置为 10 分钟,将 idle_in_transaction_session_timeout 设置为 60 秒,就能分别清理空闲连接和空闲事务。需要注意的是,有些长事务可能长时间无 SQL 执行但确实在等待外部事件,比如应用事务中等待用户输入。对于这类情况,自动终止会导致事务回滚,因此超时值需要根据业务最长处理时间合理评估,不能设置得过短。
除了这两个参数,还可以结合 statement_timeout 限制单条语句执行时间,以及 lock_timeout 限制等待锁的时间,构建更完整的会话超时体系。它们各自控制的阶段不同,组合使用能够减少数据库被异常会话长期占用的风险。
设置空闲事务自动终止的最佳实践
在实际生产环境中,不建议一开始就设置非常短的超时值。可以先通过监控采集空闲事务的平均持续时间和最大持续时间,观察应用是否存在长时间未提交但最终会正常提交的场景。如果存在,需要从应用代码层面修正事务边界,而不是单纯依赖数据库参数自动终止。
通常推荐的起始值为 60 秒或 120 秒,随后观察误杀情况,再逐步缩短到 30 秒甚至更低。对于分析型任务或批处理任务,可能需要在批处理会话中使用 SET 命令临时放宽超时,避免大批量导入过程中被误终止。
此外,自动终止后应用会收到连接被终止的错误,因此客户端需要具备重连和事务重试机制。如果使用连接池,连接被终止后会由连接池重新建立,但未提交的更改会丢失,必须确保业务可以处理这种失败。最后,定期审计 pg_stat_activity 中 idle in transaction 的来源,定位到具体的应用模块和 SQL,才是解决空闲事务问题的根本方式。
PostgreSQL空闲事务自动终止修改时间:2026-08-30 08:01:14