feat: 添加服务和数据库初始化
This commit is contained in:
137
database/mysql.go
Normal file
137
database/mysql.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.hujye.com/infrastructure/go-web-gin/config"
|
||||
"git.hujye.com/infrastructure/go-web-gin/logger"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
gormlogger "gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
db *gorm.DB
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
// gormLogger implements gorm/logger.Interface using project's zap logger
|
||||
type gormLogger struct {
|
||||
logLevel gormlogger.LogLevel
|
||||
}
|
||||
|
||||
// newGormLogger creates a new gorm logger
|
||||
func newGormLogger(level gormlogger.LogLevel) *gormLogger {
|
||||
return &gormLogger{logLevel: level}
|
||||
}
|
||||
|
||||
// LogMode sets log level
|
||||
func (l *gormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface {
|
||||
newLogger := *l
|
||||
newLogger.logLevel = level
|
||||
return &newLogger
|
||||
}
|
||||
|
||||
// Info logs info messages
|
||||
func (l *gormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.logLevel >= gormlogger.Info {
|
||||
logger.GetLogger().Info(ctx, fmt.Sprintf("gorm: %s", fmt.Sprintf(msg, data...)))
|
||||
}
|
||||
}
|
||||
|
||||
// Warn logs warn messages
|
||||
func (l *gormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.logLevel >= gormlogger.Warn {
|
||||
logger.GetLogger().Warn(ctx, fmt.Sprintf("gorm: %s", fmt.Sprintf(msg, data...)))
|
||||
}
|
||||
}
|
||||
|
||||
// Error logs error messages
|
||||
func (l *gormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
|
||||
if l.logLevel >= gormlogger.Error {
|
||||
logger.GetLogger().Error(ctx, fmt.Sprintf("gorm: %s", fmt.Sprintf(msg, data...)))
|
||||
}
|
||||
}
|
||||
|
||||
// Trace logs sql query with execution time
|
||||
func (l *gormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||
if l.logLevel <= gormlogger.Silent {
|
||||
return
|
||||
}
|
||||
|
||||
elapsed := time.Since(begin)
|
||||
sql, rows := fc()
|
||||
|
||||
switch {
|
||||
case err != nil && l.logLevel >= gormlogger.Error:
|
||||
logger.GetLogger().Error(ctx, "gorm query error", "duration", elapsed.Milliseconds(), "sql", sql, "rows", rows, "error", err.Error())
|
||||
case elapsed > 200*time.Millisecond && l.logLevel >= gormlogger.Warn:
|
||||
logger.GetLogger().Warn(ctx, "gorm slow query", "duration", elapsed.Milliseconds(), "sql", sql, "rows", rows)
|
||||
case l.logLevel >= gormlogger.Info:
|
||||
logger.GetLogger().Debug(ctx, "gorm query", "duration", elapsed.Milliseconds(), "sql", sql, "rows", rows)
|
||||
}
|
||||
}
|
||||
|
||||
// GetDB returns the gorm.DB singleton instance
|
||||
// It will initialize the connection on first call
|
||||
func GetDB() *gorm.DB {
|
||||
once.Do(func() {
|
||||
db = initDB()
|
||||
})
|
||||
return db
|
||||
}
|
||||
|
||||
// initDB initializes and returns a new gorm.DB connection
|
||||
func initDB() *gorm.DB {
|
||||
cfg := config.Get().MySQL
|
||||
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%t&loc=Local",
|
||||
cfg.User,
|
||||
cfg.Password,
|
||||
cfg.Host,
|
||||
cfg.Port,
|
||||
cfg.DBName,
|
||||
cfg.Charset,
|
||||
cfg.ParseTime,
|
||||
)
|
||||
|
||||
var logLevel gormlogger.LogLevel
|
||||
if config.Get().IsDebug() {
|
||||
logLevel = gormlogger.Info
|
||||
} else {
|
||||
logLevel = gormlogger.Silent
|
||||
}
|
||||
|
||||
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||
Logger: newGormLogger(logLevel),
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to connect to database: %v", err))
|
||||
}
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to get database instance: %v", err))
|
||||
}
|
||||
|
||||
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
||||
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
||||
sqlDB.SetConnMaxLifetime(time.Duration(cfg.ConnMaxLifetime) * time.Second)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// Close closes the database connection
|
||||
func Close() error {
|
||||
if db != nil {
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDB.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
69
database/redis.go
Normal file
69
database/redis.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.hujye.com/infrastructure/go-web-gin/config"
|
||||
"git.hujye.com/infrastructure/go-web-gin/logger"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var (
|
||||
rdb *redis.Client
|
||||
redisOnce sync.Once
|
||||
)
|
||||
|
||||
// GetRedis returns the redis.Client singleton instance.
|
||||
// It will initialize the connection on first call
|
||||
func GetRedis() *redis.Client {
|
||||
redisOnce.Do(func() {
|
||||
rdb = initRedis()
|
||||
})
|
||||
return rdb
|
||||
}
|
||||
|
||||
// initRedis initializes and returns a new redis.Client connection.
|
||||
// It will panic if connection fails
|
||||
func initRedis() *redis.Client {
|
||||
cfg := config.Get().Redis
|
||||
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.Addr,
|
||||
Password: cfg.Password,
|
||||
DB: cfg.DB,
|
||||
PoolSize: cfg.PoolSize,
|
||||
MinIdleConns: cfg.MinIdleConns,
|
||||
MaxRetries: cfg.MaxRetries,
|
||||
DialTimeout: time.Duration(cfg.DialTimeout) * time.Second,
|
||||
ReadTimeout: time.Duration(cfg.ReadTimeout) * time.Second,
|
||||
WriteTimeout: time.Duration(cfg.WriteTimeout) * time.Second,
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := rdb.Ping(ctx).Err(); err != nil {
|
||||
logger.GetLogger().Error(nil, "redis connect failed", "addr", cfg.Addr, "error", err.Error())
|
||||
panic(fmt.Sprintf("failed to connect to redis: %v", err))
|
||||
}
|
||||
|
||||
logger.GetLogger().Info(nil, "redis connected successfully", "addr", cfg.Addr, "db", cfg.DB)
|
||||
|
||||
return rdb
|
||||
}
|
||||
|
||||
// CloseRedis closes the redis connection.
|
||||
// Returns error if close fails, nil otherwise
|
||||
func CloseRedis() error {
|
||||
if rdb != nil {
|
||||
if err := rdb.Close(); err != nil {
|
||||
logger.GetLogger().Error(nil, "redis close failed", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
logger.GetLogger().Info(nil, "redis connection closed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user