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. 连接参数配置问题
确保连接字符串中包含正确的参数,特别是 parseTime 和 timeout 参数:
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_timeout 和 interactive_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
}
主要检查以下几点:
- 连接字符串中的超时参数配置
- MySQL服务器的
wait_timeout设置 - 网络防火墙是否允许3306端口通信
- 使用
db.Ping()验证连接而非仅调用sql.Open()

