必须用pgxpool.parseconfig显式配置连接池参数,不能仅用pgxpool.new;需设置maxconns、minconns、healthcheckperiod及afterconnect回调,并严格遵循事务、批量、时区等最佳实践。

pgxpool 连接池必须用 ParseConfig 显式配置,不能只靠 New
直接 pgxpool.New(ctx, connStr) 会跳过关键参数控制,导致连接池在高并发下快速耗尽或堆积 stale connection。生产环境必须用 pgxpool.ParseConfig 解析连接字符串,再手动设参。
-
MaxConns建议设为int32(runtime.NumCPU() * 3),但不超过数据库max_connections的 70% -
MinConns设为MaxConns / 5,避免冷启动时频繁建连 -
HealthCheckPeriod设为30 * time.Second,配合AfterConnect执行SET application_name = 'auth-service'和SET timezone = 'UTC' - 别漏掉
config.ConnConfig.RuntimeParams—— 这是控制会话级参数(如search_path)的唯一入口
事务内所有操作必须走 *pgx.Tx,混用 pool.Query 就等于没事务
常见错误是:调 pool.Begin() 拿到 *pgx.Tx,却在事务体里穿插用 pool.QueryRow() 或 pool.Exec()。这些调用从连接池取新连接,完全脱离当前事务上下文,结果是部分语句自动提交、部分回滚,甚至触发 ERROR: current transaction is aborted。
- 事务开头必须
defer tx.Rollback(),成功后显式tx.Commit() - 所有
Query/Exec/QueryRow都调tx.XXX(),不是pool.XXX() - 事务超时靠
context.WithTimeout(ctx, 5*time.Second)传给pool.Begin(),不是靠 SQL 层SET statement_timeout - 扫描 NULL 字段时,struct 字段必须用指针(如
*string)或pgtype.Text类型,否则Scan()直接 panic
批量写入必须用 pgx.Batch,循环 Exec 是性能杀手
100 条 INSERT 循环调 pool.Exec() 会发 100 次网络请求,每条都经历 TCP 握手、认证、SQL 解析、计划生成;而 pgx.Batch 把它们打包成单次 wire 协议 payload,延迟压到 1/10 以内。
- batch 大小控制在
100~500条之间:太小收益低,太大可能触发 PostgreSQL 的max_stack_depth或 OOM - 构造完 batch 后,必须用
pool.SendBatch(ctx, batch)提交,不是pool.Exec() - 拿到
*pgx.BatchResults后,每条语句结果要分别调br.Exec()或br.Query(),且最后必须br.Close(),否则连接泄漏 - 字段含
NULL时,batch 参数列表里对应位置必须传nil,不能传零值(如""或0)
时间字段一律用 timestamptz + UTC,别碰 timestamp without time zone
PostgreSQL 的 timestamp 类型不带时区,Go 的 time.Time 默认按本地时区解析,跨服务器部署时极易错乱。所有表设计阶段就该强制用 timestamptz,应用层统一以 UTC 存储和传输。
- 连接池初始化时,在
AfterConnect回调里执行SET timezone = 'UTC' - 插入前确保
time.Time已调.UTC(),不要依赖数据库自动转换 - 查询结果扫描进 struct 时,字段类型必须是
time.Time,pgx 会自动按timestamptz解析为 UTC 时间 - 前端需要本地时间?由服务端转,别让客户端自己算偏移——时区规则每年变,客户端库版本不一,容易出错
连接池参数、事务隔离、批量写法、时区处理这四块,任一环节松动都会让性能断崖下跌。尤其 pgxpool.Config 里的 AfterConnect 和 HealthCheckPeriod,看似可选,实则决定连接池能否在 Kubernetes 服务发现抖动或 PG 重启后自动恢复。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











