PostgreSQL连接未关闭出现空闲事务导致连接繁忙问题排查
PostgreSQL 大量idle in transaction连接问题排查方案
状态本质说明
idle in transaction 指连接已经开启事务,最后一条SQL执行完成后,事务始终没有执行提交或回滚操作,连接会一直持有数据库资源不释放,累计到一定数量就会导致连接池占满、业务无法获取新连接。
你观察到的元数据查询是ORM类框架(如Hibernate、MyBatis、Spring Data JPA等)自动触发的,用于获取表字段的约束、自增属性、类型等元信息,用于实体类和表结构的映射校验,无需手动编写代码调用,对应SQL如下:
SELECT c.oid, a.attnum, a.attname, c.relname, n.nspname, a.attnotnull OR (t.typtype = 'd' AND t.typnotnull), a.attidentity != '' OR pg_catalog.pg_get_expr(d.adbin, d.adrelid) LIKE '%nextval(%' FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON (c.relnamespace = n.oid) JOIN pg_catalog.pg_attribute a ON (c.oid = a.attrelid) JOIN pg_catalog.pg_type t ON (a.atttypid = t.oid) LEFT JOIN pg_catalog.pg_attrdef d ON (d.adrelid = a.attrelid AND d.adnum = a.attnum) JOIN (SELECT 21826 AS oid , 9 AS attnum UNION ALL SELECT 21826, 3) vals ON (c.oid = vals.oid AND a.attnum = vals.attnum)
常见触发原因
- 事务默认配置错误:项目全局配置了
autocommit=false,所有SQL执行都会默认开启事务,框架执行完元数据查询后没有主动提交事务,直接把连接放回连接池,事务就会一直挂着 - 连接池回收规则失效:连接池没有开启废弃连接回收开关,或者回收超时时间设置过长,异常场景下事务没有回滚的话,会一直占用连接
- 框架本身Bug:部分旧版本ORM框架存在元数据查询时申请连接、执行完查询后漏提交/回滚事务的已知问题,属于框架代码缺陷
- 全局事务切面逻辑异常:如果配置了全局事务切面,把框架内部的元数据查询也纳入了事务管理,但切面的异常分支没有触发事务回滚,也会导致事务悬挂
排查与修复步骤
- 临时止损:如果业务已经出现连接不足的问题,执行以下SQL杀掉挂起超过5分钟的空闲事务连接:
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND state_change < NOW() - INTERVAL '5 minute';
- 检查连接配置:确认连接参数中
autocommit是否为true,连接池是否开启了废弃连接回收,建议将回收超时时间设置为30-60秒,同时开启回收日志,定位连接泄漏的调用栈 - 核对框架版本:查询你使用的ORM框架官方更新日志,确认当前版本是否存在元数据查询泄漏事务的已知Bug,如有则直接升级到修复后的稳定版本
- 校验全局事务配置:检查是否有全局事务切面错误拦截了框架内部的元数据查询请求,调整切面的切点范围,仅拦截业务层的事务操作
内容的提问来源于stack exchange,提问作者Sajeev
相关产品推荐
相关产品推荐

