go-sql-driversql
請求一個鏈接的函數有好幾種,執行完畢處理鏈接的方式稍有差異,大體以下:數據庫
db.Ping() 調用完畢後會立刻把鏈接返回給鏈接池。函數
db.Exec() 調用完畢後會立刻把鏈接返回給鏈接池,可是它返回的Result對象還保留這鏈接的引用,當後面的代碼須要處理結果集的時候鏈接將會被重用。spa
db.Query() 調用完畢後會將鏈接傳遞給sql.Rows類型,固然後者迭代完畢或者顯示的調用.Clonse()方法後,鏈接將會被釋放回到鏈接池。設計
db.QueryRow()調用完畢後會將鏈接傳遞給sql.Row類型,當.Scan()方法調用以後把鏈接釋放回到鏈接池。code
db.Begin() 調用完畢後將鏈接傳遞給sql.Tx類型對象,當.Commit()或.Rollback()方法調用後釋放鏈接。對象
sql.Open
的第一個參數是driver名稱,第二個參數是driver鏈接數據庫的信息,各個driver可能不一樣。DB不是鏈接,而且只有當須要使用時纔會建立鏈接,若是想當即驗證鏈接,須要用Ping()
方法,以下:err = db.Ping()if err != nil { // do something here }
sql.DB的設計就是用來做爲長鏈接使用的。不要頻繁Open, Close。比較好的作法是,爲每一個不一樣的datastore建一個DB對象,保持這些對象Open。若是須要短鏈接,那麼把DB做爲參數傳入function,而不要在function中Open, Close。事務
若是方法包含Query
,那麼這個方法是用於查詢並返回rows的。其餘狀況應該用Exec()
。string
var ( id int name string ) rows, err := db.Query("select id, name from users where id = ?", 1)if err != nil { log.Fatal(err) } defer rows.Close()for rows.Next() { err := rows.Scan(&id, &name) if err != nil { log.Fatal(err) } log.Println(id, name) } err = rows.Err()if err != nil { log.Fatal(err) }
上面代碼的過程爲:db.Query()
表示向數據庫發送一個query,defer rows.Close()
很是重要,遍歷rows使用rows.Next()
, 把遍歷到的數據存入變量使用rows.Scan()
, 遍歷完成後檢查error。有幾點須要注意:it
檢查遍歷是否有error
結果集(rows)未關閉前,底層的鏈接處於繁忙狀態。當遍歷讀到最後一條記錄時,會發生一個內部EOF錯誤,自動調用rows.Close()
,可是若是提早退出循環,rows不會關閉,鏈接不會回到鏈接池中,鏈接也不會關閉。因此手動關閉很是重要。rows.Close()
能夠屢次調用,是無害操做。
err在Scan
後才產生,因此能夠以下寫:
var name stringerr = db.QueryRow("select name from users where id = ?", 1).Scan(&name)if err != nil { log.Fatal(err) } fmt.Println(name)
通常用Prepare()和Exec()
完成INSERT
, UPDATE
, DELETE
操做。
db.Begin()
開始事務,Commit()
或 Rollback()
關閉事務。Tx
從鏈接池中取出一個鏈接,在關閉以前都是使用這個鏈接。Tx不能和DB層的BEGIN
, COMMIT
混合使用。
若是你須要經過多條語句修改鏈接狀態,你必須使用Tx,例如:
建立僅對單個鏈接可見的臨時表
設置變量,例如SET @var := somevalue
改變鏈接選項,例如字符集,超時
若是循環中發生錯誤會自動運行rows.Close()
,用rows.Err()
接收這個錯誤,Close方法能夠屢次調用。循環以後判斷error是很是必要的。
若是你在rows遍歷結束以前退出循環,必須手動關閉
當須要鏈接,且鏈接池中沒有可用鏈接時,新的鏈接就會被建立。
默認沒有鏈接上限,這可能會致使數據庫產生錯誤「too many connections」
db.SetMaxIdleConns(N)
設置最大空閒鏈接數
db.SetMaxOpenConns(N)
設置最大打開鏈接數
長時間保持空閒鏈接可能會致使db timeout