You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go程序实现MySQL数据库循环重连(含超时与环境变量配置)

Go 数据库连接自动重试与超时控制实现

你的需求是在init函数中实现数据库连接的重试机制,具体要求:

  • 连接失败时等待后循环重试
  • 默认超时60秒,超时未成功则退出程序
  • 支持通过环境变量OVERRIDE覆盖默认超时时间

现有代码问题分析

你的现有代码存在几个关键问题:

  1. sql.Open("mysql", dsn())只是初始化连接池,不会实际建立数据库连接,必须调用db.Ping()才能确认连接成功
  2. 没有实现连接失败后的重试逻辑
  3. 未处理超时控制,也没有用到OVERRIDE环境变量
  4. 错误处理不严谨,连接失败后直接执行后续操作会导致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() {
    // 主程序业务逻辑
}

关键实现说明

  1. 超时时间处理:
    • 读取OVERRIDE环境变量并转换为整数,处理格式错误时 fallback 到默认60秒
  2. 超时控制:
    • 使用context.WithTimeout创建超时上下文,超时后立即终止重试并退出程序
  3. 重试逻辑:
    • 循环中先检查是否超时,未超时则尝试连接
    • 连接或校验失败后等待1秒重试(等待时间可根据需求调整)
  4. 连接有效性校验:
    • 必须调用db.PingContext(ctx)确认连接成功,sql.Open仅初始化连接池不实际建立连接
  5. 资源与错误优化:
    • 重试失败后关闭当前连接避免资源泄漏
    • 创建表失败直接退出,因为后续逻辑依赖该表
  6. 性能与约束优化:
    • 用COUNT(*)统计记录数,比遍历所有行更高效
    • 给ShortUrl添加UNIQUE约束,符合短链接唯一性需求

内容的提问来源于stack exchange,提问作者user19880359

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:40:38