用 pgxpool.connect 配连接池,设 maxconns 控制大小,程序退出前调 close();查单行用 queryrow 并 scan,多行用 query 并 close;批量用 pgx.batch,建表优先 timestamptz。

pgx 连接池怎么配才不泄漏内存
用 pgxpool.Connect 而不是 pgx.Connect,后者只建单连接,没池、不复用、一请求一连就崩。连接池必须显式关闭,否则 goroutine 和 socket 会一直挂着。
-
pgxpool.Connect返回的*pgxpool.Pool需在程序退出前调用Close(),比如 defer pool.Close() 或在 main 结束时关 - 连接池大小别硬写死,用
pgxpool.Config.MaxConns控制上限,小服务设 10~20 足够,大并发看pg_stat_activity实时观察 - 环境变量里传 DSN 时,记得加
sslmode=disable(本地开发)或sslmode=require(生产),漏了会卡住连接、超时后报dial tcp: i/o timeout
Query 和 QueryRow 该选哪个
查单行且确定有结果,用 QueryRow;查多行、不确定条数、要遍历,用 Query。错用会导致 panic 或漏数据——QueryRow 遇到零行直接返回 sql.ErrNoRows,而 Query 遇到零行只是返回空结果集,不会报错。
-
QueryRow后必须调Scan(),否则连接不会归还池里,积压后触发context deadline exceeded -
Query返回*pgx.Rows,用完必须rows.Close(),不然连接一直被占着,哪怕用for rows.Next()遍历完了也不自动关 - 想查一行但字段可能为空?别用
QueryRow.Scan(&v)直接扫,改用Scan(&sql.NullString{})或 struct tag 加pgtype:"text"配合自定义类型
批量插入为什么比 for 循环快十倍
因为 pgx.Batch 把多条语句打包成一个网络往返,避免 TCP 握手和 PostgreSQL 解析开销。普通 for 循环每 insert 一次都走完整 round-trip,QPS 直接掉到 1/10。
- 用
pool.Begin()开事务 +batch := &pgx.Batch{}累积语句 +br := pool.SendBatch(ctx, batch)提交,比pool.Exec单条快得多 - batch 大小建议控制在 100~1000 条之间,太大容易 OOM 或触发 PostgreSQL 的
max_stack_depth限制 - 注意 batch 不支持 RETURNING,要拿插入后的 ID?得切回单条
QueryRow或改用INSERT ... SELECT UNNEST(...)方式
time.Time 存进 PostgreSQL 总是差 8 小时
根本原因是 Go 默认用本地时区解析 time.Time,而 PostgreSQL 的 timestamp without time zone 按 UTC 存,timestamp with time zone 才存时区信息。两边时区没对齐,就偏移。
立即学习“go语言免费学习笔记(深入)”;
- 建表时优先用
timestamptz(即timestamp with time zone),Go 侧time.Time值自带时区信息,pgx 能自动转换 - 如果必须用
timestamp(无时区),写入前统一转成 UTC:t.UTC(),读出来再按需转本地时区 - 别依赖
time.Local,Docker 容器或 Linux 服务器上它可能是 UTC,本地 macOS 可能是 CST,行为不一致
最麻烦的其实是 NULL 时间字段和零值时间混在一起——Go 的 time.Time{} 是 0001-01-01,PostgreSQL 当成非法时间报 invalid input syntax for type timestamp。得用 *time.Time 或 pgtype.Timestamptz 显式处理空值。











