關於Golang中database/sql包的學習

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()方法調用後釋放鏈接。對象

    鏈接DB

    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。事務

    讀取DB

    若是方法包含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

    1. 檢查遍歷是否有error

    2. 結果集(rows)未關閉前,底層的鏈接處於繁忙狀態。當遍歷讀到最後一條記錄時,會發生一個內部EOF錯誤,自動調用rows.Close(),可是若是提早退出循環,rows不會關閉,鏈接不會回到鏈接池中,鏈接也不會關閉。因此手動關閉很是重要。rows.Close()能夠屢次調用,是無害操做。

    單行Query

    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()完成INSERTUPDATEDELETE操做。

    事務

    db.Begin()開始事務,Commit() 或 Rollback()關閉事務。Tx從鏈接池中取出一個鏈接,在關閉以前都是使用這個鏈接。Tx不能和DB層的BEGINCOMMIT混合使用。

    若是你須要經過多條語句修改鏈接狀態,你必須使用Tx,例如:

    • 建立僅對單個鏈接可見的臨時表

    • 設置變量,例如SET @var := somevalue

    • 改變鏈接選項,例如字符集,超時

    處理Error

    循環Rows的Error

    若是循環中發生錯誤會自動運行rows.Close(),用rows.Err()接收這個錯誤,Close方法能夠屢次調用。循環以後判斷error是很是必要的。

    關閉Resultsets時的error

    若是你在rows遍歷結束以前退出循環,必須手動關閉

關於鏈接池

  1. 當須要鏈接,且鏈接池中沒有可用鏈接時,新的鏈接就會被建立。

  2. 默認沒有鏈接上限,這可能會致使數據庫產生錯誤「too many connections」

  3. db.SetMaxIdleConns(N)設置最大空閒鏈接數

  4. db.SetMaxOpenConns(N)設置最大打開鏈接數

  5. 長時間保持空閒鏈接可能會致使db timeout

相關文章
相關標籤/搜索