This commit is contained in:
vipg
2026-02-09 16:03:19 +08:00
parent d4000088a5
commit 4541b322b3
29 changed files with 0 additions and 1377 deletions

View File

@@ -1,136 +0,0 @@
// common/db/postgres.go
package db
import (
"context"
"database/sql"
"fmt"
"sync"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// 全局单例连接,避免重复创建连接(连接池全局复用)
var (
pgInstance *gorm.DB
pgOnce sync.Once
pgErr error
)
// InitPostgres 初始化PostgreSQL连接单例模式仅执行一次
// 入参:选项模式的配置函数,用户可灵活配置
// 返回:原生*gorm.DB + 错误业务层可直接使用GORM所有方法
func InitPostgres(opts ...PostgresOption) (*gorm.DB, error) {
pgOnce.Do(func() {
// 加载默认配置 + 覆盖用户自定义配置
options := defaultPostgresOptions()
for _, opt := range opts {
opt(options)
}
// 校验必传配置(账号、密码、数据库名不能为空)
if options.User == "" || options.Password == "" || options.DBName == "" {
pgErr = fmt.Errorf("postgres config error: user/password/dbname can not be empty")
return
}
// 拼接PostgreSQL DSN数据源名称GORM官方规范
dsn := fmt.Sprintf(
"host=%s port=%s user=%s password=%s dbname=%s sslmode=%s TimeZone=%s",
options.Host,
options.Port,
options.User,
options.Password,
options.DBName,
options.SSLMode,
options.TimeZone,
)
// 配置GORM日志按传入的日志级别生产环境可关闭
gormConfig := &gorm.Config{
Logger: logger.Default.LogMode(options.LogLevel),
}
// 建立GORM连接
pgInstance, pgErr = gorm.Open(postgres.Open(dsn), gormConfig)
if pgErr != nil {
pgErr = fmt.Errorf("postgres connect failed: %w", pgErr)
return
}
// 获取底层*sql.DB配置连接池关键避免连接泄漏提升性能
sqlDB, err := pgInstance.DB()
if err != nil {
pgErr = fmt.Errorf("get postgres sql.DB failed: %w", err)
return
}
// 设置连接池参数
sqlDB.SetMaxOpenConns(options.MaxOpenConns)
sqlDB.SetMaxIdleConns(options.MaxIdleConns)
sqlDB.SetConnMaxLifetime(options.ConnMaxLifetime)
sqlDB.SetConnMaxIdleTime(options.ConnMaxIdleTime)
// 测试连接ping一下确保连接有效
if err := sqlDB.PingContext(context.Background()); err != nil {
pgErr = fmt.Errorf("postgres ping failed: %w", err)
pgInstance = nil // 连接失败,置空实例
return
}
})
// 单例执行完成后,返回实例和错误
return pgInstance, pgErr
}
// GetPostgres 获取全局PostgreSQL单例连接
// 业务层初始化后可通过此方法直接获取连接无需重复调用InitPostgres
func GetPostgres() (*gorm.DB, error) {
if pgInstance == nil {
return nil, fmt.Errorf("postgres not initialized, please call InitPostgres first")
}
return pgInstance, nil
}
// ClosePostgres 关闭PostgreSQL连接应用退出时调用释放资源
// 一般在main函数的defer中调用defer db.ClosePostgres()
func ClosePostgres() error {
if pgInstance == nil {
return fmt.Errorf("postgres not initialized")
}
// 获取底层*sql.DB执行关闭
sqlDB, err := pgInstance.DB()
if err != nil {
return fmt.Errorf("get postgres sql.DB failed: %w", err)
}
if err := sqlDB.Close(); err != nil {
return fmt.Errorf("close postgres failed: %w", err)
}
// 关闭后重置单例,避免重复关闭
pgOnce = sync.Once{}
pgInstance = nil
pgErr = nil
return nil
}
// PingPostgres 测试PostgreSQL连接是否有效
// 业务层可定时调用(如健康检查),确保连接未断开
func PingPostgres() error {
db, err := GetPostgres()
if err != nil {
return err
}
sqlDB, err := db.DB()
if err != nil {
return fmt.Errorf("get postgres sql.DB failed: %w", err)
}
return sqlDB.PingContext(context.Background())
}