← 中文资源

简体中文版本

PGX 连接池与查询超时

用 pgx 连接池访问 PostgreSQL:池参数显式配置、启动即 ping 验证连通、事务封装提交回滚成对、context 约束每条查询。

阅读英文原文

示例说明

pgxpool 是生产级连接池:MinConns 维持热连接避免冷启动延迟,MaxConnLifetime 强制换血防止长连接内存泄漏累积,HealthCheckPeriod 自动剔除被服务端掐断的死连接。启动 ping 是部署期快速失败——连不上就立刻报错回滚发布,而不是等到第一个请求才发现。

技术要点

  • 池参数四件套显式声明
  • 启动 ping 让配置错误即刻暴露
  • defer Rollback 提交后安全空转

代码解读

newPool 解析连接串后配置池参数,Ping 带三秒超时验证连通性,失败即关池返回错误。withTx 的 Begin 后 defer Rollback——事务已提交时回滚是无害的空操作,异常路径则保证必然回滚。主函数的查询同样跑在五秒超时的 context 里。

使用建议

池上限要乘实例数后与数据库总预算对齐。事务内禁止外部 HTTP 调用。慢查询配 statement_timeout 服务端兜底。

代码示例

package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

func newPool(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
	config, err := pgxpool.ParseConfig(databaseURL)
	if err != nil {
		return nil, fmt.Errorf("parse dsn: %w", err)
	}

	config.MaxConns = 20
	config.MinConns = 4
	config.MaxConnLifetime = 30 * time.Minute
	config.MaxConnIdleTime = 5 * time.Minute
	config.HealthCheckPeriod = 30 * time.Second

	pool, err := pgxpool.NewWithConfig(ctx, config)
	if err != nil {
		return nil, fmt.Errorf("create pool: %w", err)
	}

	pingCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
	defer cancel()
	if err := pool.Ping(pingCtx); err != nil {
		pool.Close()
		return nil, fmt.Errorf("verify connectivity: %w", err)
	}
	return pool, nil
}

func withTx(ctx context.Context, pool *pgxpool.Pool, fn func(ctx context.Context) error) error {
	tx, err := pool.Begin(ctx)
	if err != nil {
		return fmt.Errorf("begin: %w", err)
	}
	defer tx.Rollback(ctx) // 提交后回滚是空操作,安全兜底

	if err := fn(ctx); err != nil {
		return err
	}
	return tx.Commit(ctx)
}

func main() {
	pool, err := newPool(context.Background(), os.Getenv("DATABASE_URL"))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer pool.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	var version string
	if err := pool.QueryRow(ctx, "select version()").Scan(&version); err != nil {
		fmt.Println("query failed:", err)
		return
	}
	fmt.Printf("connected to: %.32s\n", version)
}