pgx连接失败主因是配置错误而非驱动问题:①host需匹配Docker容器名或宿主机IP;②云服务端口非5432须显式指定;③密码含特殊字符需url.QueryEscape处理。

pgx.Connect 为什么连不上,检查这三处
绝大多数连接失败不是驱动问题,而是配置没对上。pgx 默认不读 .env 或配置文件,所有连接参数得手动拼或显式传入。
-
host写成localhost却忘了 PostgreSQL 正在 Docker 里跑——实际该填容器名(如postgres)或宿主机 IP(172.17.0.1) -
port默认是5432,但有些云服务(如 AWS RDS)可能启用了非标端口,必须显式指定 - 密码含特殊字符(如
@、/)时,用url.QueryEscape处理再拼进连接字符串,否则pgx.ParseConfig会解析失败
推荐用 pgx.ParseConfig 而非直连字符串,便于提前校验:
cfg, err := pgx.ParseConfig("postgres://user:pass@localhost:5432/dbname")
if err != nil {
log.Fatal(err) // 这里就能捕获 URL 解析错误
}
conn, err := pgx.ConnectConfig(context.Background(), cfg)
QueryRow 和 Query 区别不清,查单行还是多行选错函数
QueryRow 是为「严格返回 0 或 1 行」设计的;Query 才用于多行结果。用错会导致 panic 或漏数据。
- 执行
SELECT COUNT(*)或SELECT id FROM users WHERE id = $1—— 用QueryRow,调Scan后自动关闭 - 执行
SELECT name, email FROM users LIMIT 10—— 必须用Query,且要手动rows.Close(),否则连接泄漏 - 即使 SQL 理论上只返回一行,如果没加
LIMIT 1或唯一约束,QueryRow.Scan遇到第二行就直接 panic,不给你机会处理
示例:
立即学习“go语言免费学习笔记(深入)”;
// ✅ 安全:明确只取一行 err := conn.QueryRow(context.Background(), "SELECT name FROM users WHERE id = $1", 123).Scan(&name) <p>// ❌ 危险:没 Close,且没处理 ErrNoRows rows, _ := conn.Query(context.Background(), "SELECT <em> FROM logs WHERE ts > $1", time.Now().Add(-24</em>time.Hour)) defer rows.Close() // 必须加
事务里 exec 失败却不 rollback,连接池被卡住
pgx 的 Begin 返回的是 *pgx.Tx,它不自动回滚。一旦中间出错没显式 Rollback,这个事务会一直占着连接,直到超时或进程退出。
- 别依赖 defer + Rollback:因为成功时也得
Commit,不能只 defer 一个操作 - 标准写法是用 if/else 分支,或封装成带 recover 的辅助函数
- 注意
tx.QueryRow等方法失败时,tx仍处于 open 状态,必须显式 rollback 才能释放连接
最小可靠模板:
tx, err := conn.Begin(context.Background())
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
tx.Rollback(context.Background())
panic(p)
}
}()
<p>_, err = tx.Exec(context.Background(), "INSERT INTO ...")
if err != nil {
tx.Rollback(context.Background())
return err
}</p><p>return tx.Commit(context.Background())
扫描时间字段时 panic:pq: parsing time 报错怎么解
PostgreSQL 的 TIMESTAMP WITH TIME ZONE 在 Go 里默认映射为 time.Time,但时区信息若和 Go 运行环境不一致,Scan 就会失败。
- 最常见原因是数据库用
UTC存储,而 Go 程序所在机器时区是Asia/Shanghai,解析时试图按本地时区解释 UTC 时间戳 - 解决方案:在连接字符串里加
timezone=utc参数,让 pgx 统一按 UTC 解析 - 或者更彻底:在
ParseConfig后手动设置cfg.RuntimeParams["timezone"] = "UTC" - 如果业务真需要本地时区显示,别在 Scan 阶段硬转,拿到
time.Time后用.In(loc)转换,避免底层解析歧义
连接配置示例:
cfg, _ := pgx.ParseConfig("postgres://user:pass@localhost:5432/db?timezone=utc")
事情说清了就结束。真正难的不是写几行 connect 代码,而是每次改配置、换环境、加字段时,都得重新核对时区、权限、连接生命周期这些隐性契约。











