golang操作MySQL幾個原則和示例

使用原則

  1. 庫自帶連接池,使用方不需自行實現。*sql.DB 線程安全,開箱即用,屏弊了底層創建連接的實現
  2. Open 只是創建類,調用一次即可,使用前需要 Ping 確保連接正常。
  3. 一定要設置連接池的兩個參數 MaxIdle, MaxOpen,否則在極端情況會把 DB 連接打滿(未加索引,大事務阻塞)。可選 MaxLifetime,需咨詢 DBA,一般 DB 默認8小時,無需設置,如果很短要視情況而定
  4. 事務會占用一個連接,盡可能減小事務耗時,打散大事務,否則會將 DB 連接數打滿
  5. prepare 會占用一個連接,每次使用完后,一定要 close ,否則同樣會將連接數打滿
  6. DSN 需要指定時區和對時間字段的支持,否則會出現時間提前8小時的問題
  7. Query, Prepare, Exec 無需業務層重試,底層已經實現

下一篇源碼走讀會詳細說明原因

連接創建示例

type MySQLClient struct {
    Host    string
    MaxIdle int
    MaxOpen int
    User    string
    Pwd     string
    DB      string
    Port    int
    pool    *sql.DB
}

func (mc *MySQLClient) Init() (err error) {
    // 構建 DSN 時尤其注意 loc 和 parseTime 正確設置
    // 東八區,允許解析時間字段
    uri := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&loc=%s&parseTime=true",
        mc.User,
        mc.Pwd,
        mc.Host,
        mc.Port,
        mc.DB,
        url.QueryEscape("Asia/Shanghai"))
    // Open 全局一個實例只需調用一次
    mc.pool, err = sql.Open("mysql", uri)
    if err != nil {
        return err
    }
    //使用前 Ping, 確保 DB 連接正常
    err = mc.pool.Ping()
    if err != nil {
        return err
    }
    // 設置最大連接數,一定要設置 MaxOpen
    mc.pool.SetMaxIdleConns(mc.MaxIdle)
    mc.pool.SetMaxOpenConns(mc.MaxOpen)
    return nil
}

數據庫查詢示例

func testQuery(beginTime, endTime, code string) ([]*OrderInfo, error) {
    db := iowrapper.MySQLClient.GetMySQL()
    err := db.Ping()
    if err != nil {
        return nil, err
    }

    var rows *sql.Rows
    // sql 可以用占位符,涉及業務分表提前生成
    rows, err = db.Query(getSqlByCode(code, beginTime, endTime))
    if err != nil {
        return nil, err
    }

    OrderInfos := make([]*OrderInfo, 0, 10)

    for rows.Next() {
        oi := &OrderInfo{}
        var createTime time.Time

        err := rows.Scan(&oi.OrderId, &createTime, &oi.StartingLng, &oi.StartingLat, &oi.DestLng, &oi.DestLat)
        if err != nil {
            continue
        }

        oi.CreateTime = createTime.Unix()
        OrderInfos = append(OrderInfos, oi)
    }

    return OrderInfos, nil
}

數據庫更新示例

func testExec() error {
    sql := "update test.table1 set _create_time=now() where id=?"
    res, err := db.Exec(sql, 7988161482)
    if err != nil {
        fmt.Println("exec error ", err.Error())
        return err
    }
    fmt.Println(res.LastInsertId())
    fmt.Println(res.RowsAffected())
    return nil
}

數據庫prepare示例

func testStmt() error {
    //占位符sql
    sql := "update test.table1 set _create_time=now() where id=?"
    stmt, err := db.Prepare(sql)
    if err != nil {
        fmt.Println("stmt error ", err.Error())
        return err
    }
    // 一定要關閉,很重要
    defer stmt.Close()

    // 可以批量,示例只有一個
    _, err = stmt.Exec(7988161474)
    if err != nil {
        fmt.Println("stmt exec error ", err.Error())
        return err
    }
    return nil
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容