Go程序实现MySQL数据库循环重连(含超时与环境变量配置)
Go 数据库连接自动重试与超时控制实现
你的需求是在init函数中实现数据库连接的重试机制,具体要求:
- 连接失败时等待后循环重试
- 默认超时60秒,超时未成功则退出程序
- 支持通过环境变量
OVERRIDE覆盖默认超时时间
现有代码问题分析
你的现有代码存在几个关键问题:
sql.Open("mysql", dsn())只是初始化连接池,不会实际建立数据库连接,必须调用db.Ping()才能确认连接成功- 没有实现连接失败后的重试逻辑
- 未处理超时控制,也没有用到
OVERRIDE环境变量 - 错误处理不严谨,连接失败后直接执行后续操作会导致panic
修改后的完整代码
import ( "context" "database/sql" "fmt" "os" "strconv" "time" _ "github.com/go-sql-driver/mysql" ) // 假设以下配置变量已提前定义 var ( username string password string ipdb string portdb string dbName string ) func dsn() string { return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", username, password, ipdb, portdb, dbName) } func init() { // 解析超时时间,默认60秒 timeoutSeconds := 60 overrideStr := os.Getenv("OVERRIDE") if overrideStr != "" { var err error timeoutSeconds, err = strconv.Atoi(overrideStr) if err != nil { fmt.Printf("OVERRIDE环境变量格式错误,使用默认超时60秒: %v\n", err) } } // 创建超时上下文,超时后自动终止重试 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSeconds)*time.Second) defer cancel() var db *sql.DB var err error // 循环执行连接重试 for { select { case <-ctx.Done(): fmt.Printf("数据库连接超时(%d秒),程序退出\n", timeoutSeconds) os.Exit(1) default: db, err = sql.Open("mysql", dsn()) if err != nil { fmt.Printf("连接初始化失败,1秒后重试: %v\n", err) time.Sleep(1 * time.Second) continue } // 实际校验连接有效性 err = db.PingContext(ctx) if err != nil { fmt.Printf("连接校验失败,1秒后重试: %v\n", err) db.Close() time.Sleep(1 * time.Second) continue } // 连接成功,退出重试循环 fmt.Printf("成功连接到MySQL服务器\nDSN: %s\n", dsn()) break } } // 处理表存在性检查与创建 defer db.Close() rows, tableCheckErr := db.Query("SELECT * FROM Url LIMIT 1;") if tableCheckErr == nil { fmt.Println("\n数据库中已存在Url表") rows.Close() // 高效统计记录数 var count int err = db.QueryRow("SELECT COUNT(*) FROM Url;").Scan(&count) if err != nil { fmt.Printf("统计记录数失败: %v\n", err) } else { fmt.Printf("记录总数: %d\n", count) } } else { fmt.Printf("\nUrl表不存在: %v\n", tableCheckErr) // 创建表并添加短链接唯一性约束 _, createErr := db.Exec("CREATE TABLE Url (LongUrl varchar(255), ShortUrl varchar(32) UNIQUE);") if createErr == nil { fmt.Println("成功创建Url表") } else { fmt.Printf("创建Url表失败: %v\n", createErr) os.Exit(1) } } } func main() { // 主程序业务逻辑 }
关键实现说明
- 超时时间处理:
- 读取
OVERRIDE环境变量并转换为整数,处理格式错误时 fallback 到默认60秒
- 读取
- 超时控制:
- 使用
context.WithTimeout创建超时上下文,超时后立即终止重试并退出程序
- 使用
- 重试逻辑:
- 循环中先检查是否超时,未超时则尝试连接
- 连接或校验失败后等待1秒重试(等待时间可根据需求调整)
- 连接有效性校验:
- 必须调用
db.PingContext(ctx)确认连接成功,sql.Open仅初始化连接池不实际建立连接
- 必须调用
- 资源与错误优化:
- 重试失败后关闭当前连接避免资源泄漏
- 创建表失败直接退出,因为后续逻辑依赖该表
- 性能与约束优化:
- 用
COUNT(*)统计记录数,比遍历所有行更高效 - 给
ShortUrl添加UNIQUE约束,符合短链接唯一性需求
- 用
内容的提问来源于stack exchange,提问作者user19880359
相关产品推荐
相关产品推荐

