mirror of
https://github.com/DullJZ/s3-balance.git
synced 2026-09-07 17:06:37 +08:00
Use modernc.org/sqlite to support CGO_ENABLED=0
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
|||||||
"gorm.io/driver/sqlite"
|
"gorm.io/driver/sqlite"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DB 全局数据库连接
|
// DB 全局数据库连接
|
||||||
@@ -23,10 +24,10 @@ var DB *gorm.DB
|
|||||||
// Initialize 初始化数据库连接
|
// Initialize 初始化数据库连接
|
||||||
func Initialize(cfg *config.DatabaseConfig) error {
|
func Initialize(cfg *config.DatabaseConfig) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// 设置日志级别
|
// 设置日志级别
|
||||||
logLevel := getLogLevel(cfg.LogLevel)
|
logLevel := getLogLevel(cfg.LogLevel)
|
||||||
|
|
||||||
// GORM配置
|
// GORM配置
|
||||||
gormConfig := &gorm.Config{
|
gormConfig := &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logLevel),
|
Logger: logger.Default.LogMode(logLevel),
|
||||||
@@ -35,7 +36,7 @@ func Initialize(cfg *config.DatabaseConfig) error {
|
|||||||
},
|
},
|
||||||
QueryFields: true,
|
QueryFields: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据数据库类型创建连接
|
// 根据数据库类型创建连接
|
||||||
switch cfg.Type {
|
switch cfg.Type {
|
||||||
case "sqlite":
|
case "sqlite":
|
||||||
@@ -47,39 +48,39 @@ func Initialize(cfg *config.DatabaseConfig) error {
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported database type: %s", cfg.Type)
|
return fmt.Errorf("unsupported database type: %s", cfg.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to connect to database: %w", err)
|
return fmt.Errorf("failed to connect to database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取底层SQL数据库连接
|
// 获取底层SQL数据库连接
|
||||||
sqlDB, err := DB.DB()
|
sqlDB, err := DB.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get sql.DB: %w", err)
|
return fmt.Errorf("failed to get sql.DB: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置连接池参数
|
// 设置连接池参数
|
||||||
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
||||||
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
||||||
sqlDB.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetime) * time.Second)
|
sqlDB.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetime) * time.Second)
|
||||||
|
|
||||||
// 测试连接
|
// 测试连接
|
||||||
if err := sqlDB.Ping(); err != nil {
|
if err := sqlDB.Ping(); err != nil {
|
||||||
return fmt.Errorf("failed to ping database: %w", err)
|
return fmt.Errorf("failed to ping database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自动迁移
|
// 自动迁移
|
||||||
if cfg.AutoMigrate {
|
if cfg.AutoMigrate {
|
||||||
if err := AutoMigrate(); err != nil {
|
if err := AutoMigrate(); err != nil {
|
||||||
return fmt.Errorf("failed to auto migrate: %w", err)
|
return fmt.Errorf("failed to auto migrate: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Successfully connected to %s database", cfg.Type)
|
log.Printf("Successfully connected to %s database", cfg.Type)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// connectSQLite 连接SQLite数据库
|
// connectSQLite 连接SQLite数据库(使用modernc.org/sqlite,支持非CGO)
|
||||||
func connectSQLite(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
func connectSQLite(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
||||||
// 创建数据目录(如果不存在)
|
// 创建数据目录(如果不存在)
|
||||||
dir := filepath.Dir(dsn)
|
dir := filepath.Dir(dsn)
|
||||||
@@ -88,31 +89,35 @@ func connectSQLite(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
|||||||
return nil, fmt.Errorf("failed to create database directory: %w", err)
|
return nil, fmt.Errorf("failed to create database directory: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加SQLite特定参数
|
// 添加SQLite特定参数
|
||||||
if dsn != ":memory:" {
|
if dsn != ":memory:" {
|
||||||
dsn = fmt.Sprintf("%s?_journal_mode=WAL&_timeout=5000&_synchronous=NORMAL&_cache_size=10000", dsn)
|
dsn = fmt.Sprintf("%s?_journal_mode=WAL&_timeout=5000&_synchronous=NORMAL&_cache_size=10000", dsn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gorm.Open(sqlite.Open(dsn), gormConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// connectMySQL 连接MySQL数据库
|
// 使用modernc.org/sqlite驱动(纯Go实现,无需CGO)
|
||||||
|
dialector := sqlite.Dialector{
|
||||||
|
DriverName: "sqlite",
|
||||||
|
DSN: dsn,
|
||||||
|
}
|
||||||
|
|
||||||
|
return gorm.Open(dialector, gormConfig)
|
||||||
|
} // connectMySQL 连接MySQL数据库
|
||||||
func connectMySQL(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
func connectMySQL(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
||||||
// MySQL DSN示例: user:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
// MySQL DSN示例: user:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
||||||
|
|
||||||
// 如果DSN中没有指定字符集,添加默认字符集
|
// 如果DSN中没有指定字符集,添加默认字符集
|
||||||
if dsn != "" {
|
if dsn != "" {
|
||||||
dsn = ensureMySQLParams(dsn)
|
dsn = ensureMySQLParams(dsn)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gorm.Open(mysql.Open(dsn), gormConfig)
|
return gorm.Open(mysql.Open(dsn), gormConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// connectPostgreSQL 连接PostgreSQL数据库
|
// connectPostgreSQL 连接PostgreSQL数据库
|
||||||
func connectPostgreSQL(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
func connectPostgreSQL(dsn string, gormConfig *gorm.Config) (*gorm.DB, error) {
|
||||||
// PostgreSQL DSN示例: host=localhost user=user password=password dbname=mydb port=5432 sslmode=disable TimeZone=Asia/Shanghai
|
// PostgreSQL DSN示例: host=localhost user=user password=password dbname=mydb port=5432 sslmode=disable TimeZone=Asia/Shanghai
|
||||||
|
|
||||||
return gorm.Open(postgres.Open(dsn), gormConfig)
|
return gorm.Open(postgres.Open(dsn), gormConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,21 +128,21 @@ func ensureMySQLParams(dsn string) string {
|
|||||||
"parseTime": "True",
|
"parseTime": "True",
|
||||||
"loc": "Local",
|
"loc": "Local",
|
||||||
}
|
}
|
||||||
|
|
||||||
separator := "?"
|
separator := "?"
|
||||||
if len(dsn) > 0 && dsn[len(dsn)-1] == '?' {
|
if len(dsn) > 0 && dsn[len(dsn)-1] == '?' {
|
||||||
separator = ""
|
separator = ""
|
||||||
} else if contains(dsn, "?") {
|
} else if contains(dsn, "?") {
|
||||||
separator = "&"
|
separator = "&"
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range params {
|
for key, value := range params {
|
||||||
if !contains(dsn, key+"=") {
|
if !contains(dsn, key+"=") {
|
||||||
dsn = fmt.Sprintf("%s%s%s=%s", dsn, separator, key, value)
|
dsn = fmt.Sprintf("%s%s%s=%s", dsn, separator, key, value)
|
||||||
separator = "&"
|
separator = "&"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dsn
|
return dsn
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,13 +185,13 @@ func AutoMigrate() error {
|
|||||||
&storage.AccessLog{},
|
&storage.AccessLog{},
|
||||||
&storage.VirtualBucketMapping{},
|
&storage.VirtualBucketMapping{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, model := range models {
|
for _, model := range models {
|
||||||
if err := DB.AutoMigrate(model); err != nil {
|
if err := DB.AutoMigrate(model); err != nil {
|
||||||
return fmt.Errorf("failed to migrate %T: %w", model, err)
|
return fmt.Errorf("failed to migrate %T: %w", model, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Database migration completed successfully")
|
log.Println("Database migration completed successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -208,15 +213,15 @@ func HealthCheck() error {
|
|||||||
if DB == nil {
|
if DB == nil {
|
||||||
return fmt.Errorf("database not initialized")
|
return fmt.Errorf("database not initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlDB, err := DB.DB()
|
sqlDB, err := DB.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
return sqlDB.PingContext(ctx)
|
return sqlDB.PingContext(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user