Files
backend_v2/internal/database/postgres.go
toom1996 299fd974df updae
2026-09-21 19:19:03 +08:00

80 lines
2.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package database 负责数据库连接的建立与生命周期管理。
//
// 这里刻意不提供包级全局 DB 变量:*gorm.DB 由 main 装配后显式注入各 repository,
// 依赖关系清晰可见,也让 repository 可以在测试中替换为独立的数据库实例。
//
// 数据库已迁移至 PostgreSQL(见 scripts/pgvector 的本地 Docker 环境)。
//
// 表结构不再由服务启动时自动迁移:全库「结构 + 索引 + 数据」统一由 cmd/dbtool 导出的
// 纯 SQL 维护(dbtool dump → psql -f)。原 database.AutoMigrate / EnsureDedupSchema
// 已随此决策移除 —— 本项目结构定义现在只有一个来源,就是那份 dump 脚本。
// 因此本包只负责「连接」这一件事,不执行任何 DDL。
package database
import (
"fmt"
"time"
"fashionapi/internal/config"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// New 建立 PostgreSQL 连接并完成连接池设置。
func New(cfg config.DatabaseConfig) (*gorm.DB, error) {
db, err := gorm.Open(postgres.Open(cfg.DSN()), &gorm.Config{
Logger: logger.Default.LogMode(parseLogLevel(cfg.LogLevel)),
// 关闭默认事务可显著提升只读接口的吞吐;写操作按需显式开启事务
SkipDefaultTransaction: true,
})
if err != nil {
return nil, fmt.Errorf("连接数据库失败: %w", err)
}
sqlDB, err := db.DB()
if err != nil {
return nil, fmt.Errorf("获取底层连接池失败: %w", err)
}
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
sqlDB.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetime) * time.Second)
// 空闲回收:定期关闭空闲连接,避免持有被服务端回收的死连接。
// 仅当配置 > 0 时启用(0 = 沿用旧行为,不回收)。
if cfg.ConnMaxIdleTime > 0 {
sqlDB.SetConnMaxIdleTime(time.Duration(cfg.ConnMaxIdleTime) * time.Second)
}
// 立刻探活,避免"启动成功但首个请求才报错"
if err := sqlDB.Ping(); err != nil {
return nil, fmt.Errorf("数据库 Ping 失败: %w", err)
}
return db, nil
}
// Close 关闭数据库连接池。
func Close(db *gorm.DB) error {
if db == nil {
return nil
}
sqlDB, err := db.DB()
if err != nil {
return err
}
return sqlDB.Close()
}
func parseLogLevel(s string) logger.LogLevel {
switch s {
case "silent":
return logger.Silent
case "error":
return logger.Error
case "info":
return logger.Info
default:
return logger.Warn
}
}