示例说明
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)
}