Files
SproutGate/sproutgate-backend/internal/database/db.go

116 lines
2.8 KiB
Go
Raw 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
import (
"fmt"
"log"
"os"
"strings"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// loadDotEnv 在当前工作目录查找 .env 文件并加载到进程环境变量中(已存在的变量不覆盖)。
// 仅用于本地开发场景:生产部署通过 docker-compose / 容器环境变量直接注入,没有 .env 文件时静默跳过。
func loadDotEnv() {
data, err := os.ReadFile(".env")
if err != nil {
return
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
continue
}
key = strings.TrimSpace(key)
if key == "" {
continue
}
if _, exists := os.LookupEnv(key); exists {
continue
}
os.Setenv(key, strings.TrimSpace(value))
}
}
// DBConfig holds MySQL connection parameters.
type DBConfig struct {
Host string
Port string
User string
Password string
DBName string
}
func (c DBConfig) DSN() string {
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
c.User, c.Password, c.Host, c.Port, c.DBName)
}
// envConfig 从环境变量读取连接参数。Host/User/Password 没有内置默认值,必须由
// 部署环境(本地 shell、.env、docker-compose 等显式提供DBName 默认统一为
// "sproutgate",开发和生产环境共用同一个库名。
func envConfig() (DBConfig, error) {
host := os.Getenv("DB_HOST")
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
if host == "" || user == "" || password == "" {
return DBConfig{}, fmt.Errorf("缺少数据库环境变量,请设置 DB_HOST/DB_USER/DB_PASSWORD或直接设置 DB_DSN")
}
port := os.Getenv("DB_PORT")
if port == "" {
port = "3306"
}
dbName := os.Getenv("DB_NAME")
if dbName == "" {
dbName = "sproutgate"
}
return DBConfig{Host: host, Port: port, User: user, Password: password, DBName: dbName}, nil
}
// Open 根据环境变量打开数据库连接。
// 优先级DB_DSN完整自定义连接串> DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME
func Open() (*gorm.DB, error) {
loadDotEnv()
dsn := os.Getenv("DB_DSN")
if dsn == "" {
cfg, err := envConfig()
if err != nil {
return nil, err
}
dsn = cfg.DSN()
log.Printf("[database] 使用数据库 %s:%s/%s", cfg.Host, cfg.Port, cfg.DBName)
} else {
log.Println("[database] 使用自定义 DB_DSN")
}
logLevel := logger.Info
if os.Getenv("GIN_MODE") == "release" {
logLevel = logger.Warn
}
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logLevel),
})
if err != nil {
return nil, fmt.Errorf("连接数据库失败: %w", err)
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(5)
return db, nil
}