package database import ( "context" "database/sql" "fmt" "time" _ "github.com/go-sql-driver/mysql" ) type Config struct { Host string Port int User string Password string DBName string MaxConns int MinConns int } func (c Config) DSN() string { return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true&charset=utf8mb4&collation=utf8mb4_unicode_ci&loc=Local", c.User, c.Password, c.Host, c.Port, c.DBName) } func NewDB(cfg Config) (*sql.DB, error) { db, err := sql.Open("mysql", cfg.DSN()) if err != nil { return nil, fmt.Errorf("open database: %w", err) } if cfg.MaxConns > 0 { db.SetMaxOpenConns(cfg.MaxConns) } if cfg.MinConns > 0 { db.SetMaxIdleConns(cfg.MinConns) } db.SetConnMaxLifetime(30 * time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { db.Close() return nil, fmt.Errorf("ping database: %w", err) } return db, nil } func NewDBFromDSN(dsn string) (*sql.DB, error) { db, err := sql.Open("mysql", dsn) if err != nil { return nil, fmt.Errorf("open database: %w", err) } db.SetMaxOpenConns(25) db.SetMaxIdleConns(5) db.SetConnMaxLifetime(30 * time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { db.Close() return nil, fmt.Errorf("ping database: %w", err) } return db, nil }