本文由簡體中文內容自動轉碼而成。阿里雲不保證此自動轉碼的準確性、完整性及時效性。本文内容請以簡體中文版本為準。

使用Go驅動包Go-MySQL-Driver串連MySQL資料庫

更新時間:2025-02-18 19:11

如果您的應用側使用Go語言,且資料庫連接建立頻繁(例如短串連情境)或串連數量較大(大於MySQL資料庫的串連數限制),您可以參考本教程通過Go驅動包Go-MySQL-Driver串連RDS MySQL資料庫,降低串連建立頻率以減少資料庫主線程的開銷。此外,本文還提供串連後操作RDS MySQL資料庫的方法。

說明

Go-MySQL-Driver為Go語言的第三方資料庫驅動包,支援串連MySQL與MariaDB資料庫,詳情請參見Go-MySQL-Driver

使用限制

RDS MySQL執行個體的資料庫版本僅支援5.7、8.0。

準備工作

  • 已下載並安裝Go環境,建議安裝Go 1.20及以上版本。

  • 已將用戶端IP地址添加至RDS執行個體白名單中。具體操作,請參見設定白名單

    說明

    若您的應用程式部署在阿里雲ECS伺服器上,且ECS與RDS執行個體位於同一地區和同一VPC,則無需設定IP白名單。

使用Go-MySQL-Driver串連資料庫

1. 依賴引入

  1. 在Go專案的go.mod檔案中,添加go-sql-driver依賴:

    require (
        github.com/go-sql-driver/mysql v1.8.1
    )
  2. .go檔案中匯入如下包:

    import (
        // 引入Go語言的 database/sql 包,它提供了通用的SQL介面
        "database/sql"
        // 引入fmt包,它是Go語言標準庫中用于格式化輸入輸出的包
        "fmt"
        // 該驅動可在Go語言中串連和操作MySQL資料庫
        "github.com/go-sql-driver/mysql"
        // 引入了Go語言的time包,用於處理時間相關的操作
        "time"
    )

2. 串連池初始化

.go檔案的main方法中初始化串連池並配置以下參數,樣本如下:

// 建立一個資料庫連接
cfg := mysql.NewConfig()
cfg.User = "****"       //您需手動替換為實際資料庫使用者名稱
cfg.Passwd = "****"     //您需手動替換為實際資料庫密碼
cfg.Net = "tcp"         //連線類型為TCP,保持預設,無需您手動修改
cfg.Addr = "rm-2zefwjx1s8156******.mysql.rds.aliyuncs.com:3306" //您需手動替換為實際MySQL資料庫連接地址和連接埠號碼
cfg.DBName = "****"     //您需手動替換為實際資料庫名稱

conn, err := mysql.NewConnector(cfg)
if err != nil {
    panic(err.Error())
}

db := sql.OpenDB(conn)
defer func(db *sql.DB) {
    err := db.Close()
    if err != nil {
        fmt.Printf("Error closing database connection: %v\n", err)
    }
}(db)
// 設定串連池參數
db.SetMaxOpenConns(20)                 // 設定串連池中最大開啟的串連數,您可根據實際需要手動調整
db.SetMaxIdleConns(2)                  // 設定串連池中最大閒置串連數,您可根據實際需要手動調整
db.SetConnMaxIdleTime(10 * time.Second) // 串連在串連池中的最長的空閑時間,您可根據實際需要手動調整
db.SetConnMaxLifetime(80 * time.Second) // 設定串連的最大生命週期,您可根據實際需要手動調整
說明

RDS MySQL資料庫連接地址和連接埠的擷取方法,請參見查看和管理執行個體串連地址和連接埠

附錄:串連池關鍵參數配置

重要
  • 推薦配置“推薦配置的參數”模組,降低資料庫運行風險;您可以選擇性配置“可選擇配置的參數模組”,以提升使用效能。

  • 為了最大程度地避免潛在的風險和不確定性,您在將新的參數值用於生產環境前,建議至少進行一輪完整的功能測試和效能測試,以確保系統穩定性和可靠性。

推薦配置的參數
可選擇配置的參數

參數名

含義

預設值

推薦值

說明

maxIdleTime

設定最大空閑時間(單位:分鐘)。

0

10~30

  • 預設值0表示不逾時。

  • 建議根據應用程式的實際需求配置該參數。可通過SetConnMaxIdleTime方法進行設定。

maxLifetime

設定串連的生命週期時間(單位:小時)。

0

1~8

  • 預設值0表示永久存在,即沒有設定最大生命週期。

  • 設定該參數是為防止串連長時間存在,浪費資源。可通過SetConnMaxLifetime方法進行設定。

maxOpen

設定串連池中允許的最大串連數。

0

100

  • 預設值0表示沒有限制。

  • 如果MaxIdleConns大於0且新的MaxOpenConns小於MaxIdleConns,則MaxIdleConns將被縮減以匹配新的MaxOpenConns限制。

  • 建議根據應用程式的實際需求配置該參數。可通過SetMaxOpenConns方法進行設定。

maxIdleCount

設定串連池中允許的最大空閑串連數。

2

20

  • 適當配置該參數可以預留一定數量的串連,快速處理突發增加的資料庫請求。

  • 如果MaxOpenConns大於0但小於新的MaxIdleConns,則新的MaxIdleConns將被縮減以匹配MaxOpenConns的限制。

  • 可通過SetMaxIdleConns方法進行設定。

  • 如果設定傳入的參數n <= 0,則不會保留空閑串連。

readTimeout

I/O讀取的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。

0

10000ms-60000ms

  • 預設值0表示沒有逾時限制。建議保持預設值,如果要修改此值,請根據實際業務調整。

  • 請使用Go標準庫time.Duration類型直接賦值,通過預定義單位常量設定,例如cfg.readTimeout = 30*time.Second,避免使用字串格式(例如30s)。

writeTimeout

I/O寫入的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。

0

10000ms-60000ms

  • 預設值0表示沒有逾時限制。建議保持預設值,如果要修改此值,請根據實際業務調整。

  • 請使用Go標準庫time.Duration類型直接賦值,通過預定義單位常量設定,例如cfg.writeTimeout=30*time.Second,避免使用字串格式(例如30s)。

參數名

含義

預設值

推薦值

說明

timeout

串連建立的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)。

預設值是根據作業系統的預設值來設定。

3000ms

  • 請使用Go標準庫time.Duration類型直接賦值,通過預定義單位常量設定,例如cfg.timeout=30*time.Second,避免使用字串格式(例如30s)。

  • 建立時的配置,建議設定1~10秒之間,取決於網路品質高低,以及應用端與服務端的距離。

操作資料庫

建立表

本文以建立一個名為 userinfo 的表為例示範。

_, err = db.Exec("create table  if not exists userinfo( uid int auto_increment, username varchar(20) not null default '', departname varchar(20) not null default '', created varchar(10) not null default '', primary key(uid) );")
if err != nil {
    fmt.Println("create table error ", err)
    return
}

寫入資料

本文以在 userinfo 表中寫入資料為例示範。

方法一:直接寫入資料
方法二:通過綁定參數的方式寫入資料
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
res, err := stmt.Exec("James", "Research", "2016-06-17")
id, err := res.LastInsertId()
if err != nil {
    panic(err)
}
fmt.Println(id)
result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "Linda", "Testing", "2016-06-21")
if err != nil {
    panic(err)
}
ids, err := result.LastInsertId()
fmt.Println(ids)

更新資料

本文以更新userinfo 表中的資料為例示範。

stmtUpdate, err := db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE username=?")
if err != nil {
    fmt.Println("Prepare update statement error:", err)
    return
}
resUpdate, err := stmtUpdate.Exec("Robert", "Sales", "2024-09-23", "Linda")
if err != nil {
    fmt.Println(err)
}
rowCnt, _ := resUpdate.RowsAffected()
fmt.Println(rowCnt)

查詢資料

本文以查詢 userinfo 表中username=Robert的資料為例示範。

方法一:直接查詢資料
方法二:通過綁定參數的方式執行參數化查詢
rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "Robert")
if err != nil {
    panic(err)
}
for rows.Next() {
 var username, departname, created string
 if err := rows.Scan(&username, &departname, &created); err != nil {
     fmt.Println(err)
 }
 fmt.Println("username:", username, "departname:", departname, " created:", created)
}
defer func(rows *sql.Rows) {
 err := rows.Close()
 if err != nil {
     fmt.Println(err)
 }
}(rows)
stmtQuery, err := db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
if err != nil {
    fmt.Println("prepare error", err)
    return
}
rowData, err := stmtQuery.Query("Robert")
if err != nil {
    fmt.Println("query data error", err)
    return
}
for rowData.Next() {
 var username, departname, created string
 if err := rowData.Scan(&username, &departname, &created); err != nil {
     fmt.Println(err)
 }
 fmt.Println("username:", username, "departname:", departname, "created:", created)
}
defer func(rows *sql.Rows) {
 err := rows.Close()
 if err != nil {
     fmt.Println(err)
 }
}(rowData)

刪除資料

本文以刪除userinfo 表中username=James的資料為例示範。

delStmt, _ := db.Prepare("DELETE FROM userinfo WHERE username=?")
resultDel, err := delStmt.Exec("James")
if err != nil {
    panic(err)
}
rowAffect, _ := resultDel.RowsAffected()
fmt.Println("Data deletion completed.", rowAffect)

完整樣本

package main

import (
    // 引入Go語言的 database/sql 包,它提供了通用的SQL介面
    "database/sql"
    // 引入fmt包,它是Go語言標準庫中用于格式化輸入輸出的包
    "fmt"
    // 該驅動可在Go語言中串連和操作MySQL資料庫
    "github.com/go-sql-driver/mysql"
    // 引入了Go語言的time包,用於處理時間相關的操作
    "time"
)

func main() {
    //建立一個資料庫連接
    cfg := mysql.NewConfig()
    cfg.User = "****"                                                   /*使用者名稱*/
    cfg.Passwd = "****"                                                 /*密碼*/
    cfg.Net = "tcp"                                                     /*連線類型*/
    cfg.Addr = "rm-2ze1vw17v542q6b****.mysql.pre.rds.aliyuncs.com:3306" /*串連地址*/
    cfg.DBName = "****"                                                 /*資料庫名稱*/
    cfg.Timeout = 3 * time.Second                                       /*串連到資料庫的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/
    cfg.ReadTimeout = 60 * time.Second                                  /*I/O讀取的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/
    cfg.WriteTimeout = 60 * time.Second                                 /*I/O寫入的逾時時間,您可按需指定為毫秒(ms)、秒(s)或分鐘(m)*/

    conn, err := mysql.NewConnector(cfg)
    if err != nil {
        panic(err.Error())
    }

    db := sql.OpenDB(conn)
    defer func(db *sql.DB) {
        err := db.Close()
        if err != nil {
            fmt.Printf("Error closing database connection: %v\n", err)
        }
    }(db)

    // 設定串連池參數
    db.SetMaxOpenConns(100)                 /*設定串連池中最大開啟的串連數*/
    db.SetMaxIdleConns(20)                  /*設定串連池中最大閒置串連數*/
    db.SetConnMaxIdleTime(10 * time.Minute) /*設定串連在串連池中的最長的空閑時間*/
    db.SetConnMaxLifetime(8 * time.Hour)    /*設定串連的最大生命週期*/

    // 建立一個名為 userinfo 的表
    _, err = db.Exec("create table  if not exists userinfo( uid int auto_increment, username varchar(20) not null default '', departname varchar(20) not null default '', created varchar(10) not null default '', primary key(uid) );")
    if err != nil {
        fmt.Println("create table error ", err)
        return
    }

    // 直接寫入資料
    stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
    res, err := stmt.Exec("James", "Research", "2016-06-17")
    id, err := res.LastInsertId()
    if err != nil {
        panic(err)
    }
    fmt.Println(id)

    // 通過綁定參數的方式寫入資料
    result, err := db.Exec("INSERT INTO userinfo (username, departname, created) VALUES (?, ?, ?)", "Linda", "Testing", "2016-06-21")
    if err != nil {
        panic(err)
    }
    ids, err := result.LastInsertId()
    fmt.Println(ids)

    // 更新資料
    stmtUpdate, err := db.Prepare("UPDATE userinfo SET username=?, departname=?, created=? WHERE username=?")
    if err != nil {
        fmt.Println("Prepare update statement error:", err)
        return
    }
    resUpdate, err := stmtUpdate.Exec("Robert", "Sales", "2024-09-23", "Linda")
    if err != nil {
        fmt.Println(err)
    }
    rowCnt, _ := resUpdate.RowsAffected()
    fmt.Println(rowCnt)

    // 直接查詢資料
    rows, err := db.Query("SELECT username,departname,created FROM userinfo WHERE username=?", "Robert")
    if err != nil {
        panic(err)
    }
    for rows.Next() {
        var username, departname, created string
        if err := rows.Scan(&username, &departname, &created); err != nil {
            fmt.Println(err)
        }
        fmt.Println("username:", username, "departname:", departname, "created:", created)
    }
    defer func(rows *sql.Rows) {
        err := rows.Close()
        if err != nil {
            fmt.Println(err)
        }
    }(rows)

    // 通過綁定參數的方式執行參數化查詢
    stmtQuery, err := db.Prepare("SELECT username,departname,created FROM userinfo WHERE username=?")
    if err != nil {
        fmt.Println("prepare error", err)
        return
    }
    rowData, err := stmtQuery.Query("Robert")
    if err != nil {
        fmt.Println("query data error", err)
        return
    }
    for rowData.Next() {
        var username, departname, created string
        if err := rowData.Scan(&username, &departname, &created); err != nil {
            fmt.Println(err)
        }
        fmt.Println("username:", username, "departname:", departname, "created:", created)
    }
    defer func(rows *sql.Rows) {
        err := rows.Close()
        if err != nil {
            fmt.Println(err)
        }
    }(rowData)

    // 刪除資料
    delStmt, _ := db.Prepare("DELETE FROM userinfo WHERE username=?")
    resultDel, err := delStmt.Exec("James")
    if err != nil {
        panic(err)
    }
    rowAffect, _ := resultDel.RowsAffected()
    fmt.Println("Data deletion completed.", rowAffect)
}

相關文檔

  • 本頁導讀 (1, M)
  • 使用限制
  • 準備工作
  • 使用Go-MySQL-Driver串連資料庫
  • 1. 依賴引入
  • 2. 串連池初始化
  • 附錄:串連池關鍵參數配置
  • 操作資料庫
  • 建立表
  • 寫入資料
  • 更新資料
  • 查詢資料
  • 刪除資料
  • 完整樣本
  • 相關文檔
文檔反饋