這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
使用原則
- 庫內建串連池,使用方不需自行實現。*sql.DB 安全執行緒,開箱即用,屏弊了底層建立串連的實現
- Open 只是建立類,調用一次即可,使用前需要 Ping 確保串連正常。
- 一定要設定串連池的兩個參數 MaxIdle, MaxOpen,否則在極端情況會把 DB 串連打滿(未加索引,大事務阻塞)。可選 MaxLifetime,需諮詢 DBA,一般 DB 預設8小時,無需設定,如果很短要視情況而定
- 事務會佔用一個串連,儘可能減小事務耗時,打散大事務,否則會將 DB 串連數打滿
- prepare 會佔用一個串連,每次使用完後,一定要 close ,否則同樣會將串連數打滿
- DSN 需要指定時區和對時間欄位的支援,否則會出現時間提前8小時的問題
- 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}