Golang中MySQL数据库连接的方法与实践

Golang中MySQL数据库连接的方法与实践 尝试使用 go-sql-driver/mysql 连接到 3306 端口上的 MySQL 数据库,错误信息显示 [mysql] connection.go:49 unexpected EOF。有人知道为什么会这样吗?

5 回复

根据我发给你的链接,设置 db.SetMaxIdleConns(0) 应该可以解决这个问题…

func main() {
    fmt.Println("hello world")
}

更多关于Golang中MySQL数据库连接的方法与实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,能请你发布一下你的连接代码吗? 请查看这个 Golang Mysql 连接池中出现意外的 EOF

也许 db.SetConnMaxLifetime(0) 是错误的,删除它。

func main() {
    fmt.Println("hello world")
}

我的3306端口是开放的,我也可以ping通数据库,并使用工作台登录。

func openDB() (*sql.DB, error) {
dsn := “user:password@tcp(10.164.27.162:3306)/database_name”
db, err := sql.Open(“mysql”, dsn)
if err != nil {
log.Fatal(err)
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(0)

    err = db.Ping()
    if err != nil {
    	log.Fatal(err)
    }
    return db, nil

}
func (app *application) connectToDB() (*sql.DB, error) {

    connection, err := openDB()
    if err != nil {
    	log.Fatal(err)
    }
    log.Println("Connected to MySQL")

    return connection, nil

}
type SqlDBRepo struct {

DB *sql.DB //pool holding database connections

}
const dbTimeout = time.Second * 3
func (m *SqlDBRepo) Connection() *sql.DB {

这个错误通常是由于MySQL服务器在连接过程中意外关闭了连接导致的。以下是几种常见原因和对应的解决方案:

1. 连接参数配置问题

确保连接字符串中包含正确的参数,特别是 parseTimetimeout 参数:

package main

import (
    "database/sql"
    "fmt"
    "time"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // 正确的连接字符串配置
    dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=true&loc=Local&timeout=10s&readTimeout=30s&writeTimeout=30s"
    
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 设置连接池参数
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(25)
    db.SetConnMaxLifetime(5 * time.Minute)
    
    // 测试连接
    err = db.Ping()
    if err != nil {
        panic(err)
    }
    
    fmt.Println("连接成功")
}

2. 服务器端配置问题

检查MySQL服务器的 wait_timeoutinteractive_timeout 设置:

// 检查服务器超时设置的查询
func checkServerConfig(db *sql.DB) {
    rows, err := db.Query("SHOW VARIABLES LIKE '%timeout%'")
    if err != nil {
        panic(err)
    }
    defer rows.Close()
    
    for rows.Next() {
        var variable, value string
        if err := rows.Scan(&variable, &value); err != nil {
            panic(err)
        }
        fmt.Printf("%s: %s\n", variable, value)
    }
}

3. 使用连接重试机制

实现带重试的连接逻辑:

func connectWithRetry(dsn string, maxRetries int) (*sql.DB, error) {
    var db *sql.DB
    var err error
    
    for i := 0; i < maxRetries; i++ {
        db, err = sql.Open("mysql", dsn)
        if err != nil {
            time.Sleep(time.Duration(i) * time.Second)
            continue
        }
        
        err = db.Ping()
        if err == nil {
            return db, nil
        }
        
        db.Close()
        time.Sleep(time.Duration(i) * time.Second)
    }
    
    return nil, fmt.Errorf("连接失败,重试 %d 次后仍然无法连接", maxRetries)
}

4. 完整的连接示例

package main

import (
    "database/sql"
    "fmt"
    "log"
    "time"
    _ "github.com/go-sql-driver/mysql"
)

type DatabaseConfig struct {
    Username string
    Password string
    Host     string
    Port     string
    Database string
}

func NewDB(config DatabaseConfig) (*sql.DB, error) {
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=Local&timeout=5s&readTimeout=30s&writeTimeout=30s",
        config.Username,
        config.Password,
        config.Host,
        config.Port,
        config.Database,
    )
    
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        return nil, fmt.Errorf("打开数据库连接失败: %v", err)
    }
    
    // 配置连接池
    db.SetMaxOpenConns(20)
    db.SetMaxIdleConns(10)
    db.SetConnMaxLifetime(3 * time.Minute)
    db.SetConnMaxIdleTime(1 * time.Minute)
    
    // 验证连接
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    if err := db.PingContext(ctx); err != nil {
        db.Close()
        return nil, fmt.Errorf("数据库连接测试失败: %v", err)
    }
    
    return db, nil
}

func main() {
    config := DatabaseConfig{
        Username: "root",
        Password: "password",
        Host:     "127.0.0.1",
        Port:     "3306",
        Database: "testdb",
    }
    
    db, err := NewDB(config)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    fmt.Println("MySQL数据库连接成功")
}

5. 网络问题排查

检查网络连接和防火墙设置:

func checkNetworkConnection(host string, port string) error {
    timeout := 5 * time.Second
    conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), timeout)
    if err != nil {
        return fmt.Errorf("无法连接到 %s:%s: %v", host, port, err)
    }
    defer conn.Close()
    
    fmt.Printf("网络连接 %s:%s 正常\n", host, port)
    return nil
}

主要检查以下几点:

  1. 连接字符串中的超时参数配置
  2. MySQL服务器的 wait_timeout 设置
  3. 网络防火墙是否允许3306端口通信
  4. 使用 db.Ping() 验证连接而非仅调用 sql.Open()
回到顶部