這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
接上一篇,sql package的主要實現是database/sql, sql 中比較重要的資料結構是:
- type DB
- type Row
- type Rows
- type Stmt
- Type Tx
sql.Register
sql.Register介面用於註冊資料庫驅動。第三方開發的資料庫,需要在init中調用這個介面來完成本驅動的註冊。
介面聲明為:
func Register(name string, driver driver.Driver)
如果Register被調用了兩次註冊相同name的driver,或者driver為nil,Register將會panic。
函數Open
func Open(dirverName, dataSourceName string)(*DB error)
Open函數根據傳參中的db drivername和driver-specific描述資訊開啟一個指定的資料庫,driver-specific描述資訊通常包含database name和串連資訊。不同driver所支援的dataSourceName格式可能不同。
Open一般只是驗證參數,而不會為database建立串連。如果要驗證dataSourceName所指定的串連是否有效,則需要調用Ping函數進行測試。
Open返回一個指向DB類型的指標。DB維護自己的idle connection pool,它可以安全的被多個gorutines並發使用。
Type DB
DB是database/sql中主要的資料結構,定義了各種對database的基本操作方法。
DB是一個代表了零個或更多潛在串連的串連池的database handle。它可以安全的被多個goroutine並發使用。
sql package自動的建立和釋放串連,同時它還為空白閑串連維護一個空閑池。如果資料庫有per-connection state的概念,每個狀態只能在一個事物中被可靠的觀察到。一旦DB.Begin被調用,它返回的Tx綁定到唯一的一個串連。如果針對一個事物的Commit或Rollback被調用,則該事務的串連將會被回退到DB的idle connection pool。pool的尺寸可以通過SetMaxIdleConns設定。
type DB struct { driver driver.Driver dsn string numClosed uint64 mu sync.Mutex freeConn []*driverConn numOpen int openerCh Chan struct{} closed bool dep map[finalCloser]depSet lastPut map[*driverConn]string maxIdle int maxOpen int maxLifetime time.Duration cleanerCh chan struct{}}
func (*DB) Begin
func (db *DB)Begin() (*Tx, error)
Begin啟動一個事務,事務見得隔離等級有driver決定。
func (*DB) Close
func (db *DB)Close() error
Close用於關閉資料庫,釋放所有開啟的資源。關閉資料庫是非常少有的操作,因為資料庫處理就是要長期存在,並且能夠在多個goroutine中共用。
func (*DB) Driver
func (db *DB)Driver() driver.Driver
Driver函數返回資料庫的底層驅動資訊。
func (*DB) Exec
func (db *DB)Exec(query string, args ...interface{}) (Result, error)
Exec執行的Query不會返回任何行。
type Result是對一條SQL語句執行的總結。Result包含兩個方法: LastInsertId返回資料庫執行一條命令所產生的整形值。通常是插入一新行時的“auto increment”欄位。RowsAffected返回update、insert或delete操作所影響的行號。並不是所有的資料庫或資料庫驅動都支援這兩個特徵。
type Result interface { LastInsertId() (int64, error) RowsAffected()(int64, error)}
func (*DB) Ping
func (db *DB) Ping() error
ping函數用於驗證到資料庫的串連是否還是alive的狀態。如果連結非alive狀態,則建立串連。
func (*DB) Prepare
func (db *DB) Prepare(query string) (*Stmt, error)
Prepare函數準備一個statement用於稍後的queries和executions。多個Queries和executions可以通過Prepare返回的statement並發執行。當不再使用statement是,調用者必須調用statement的Close方法關閉statement。
func (*DB) Query
func (db *DB) Query(query string, args ...interface{})(*Rows, error)
Query函數執行對資料庫的Query並返回執行結果Rows的指標,可以有後文提到的Rows提供的方法迭代遍曆所有的結果。
func (*DB) QueryRow
func (db *DB) QueryRow(query string, args ...interface{}) *Row
QureyRow用於最多隻有一行返回的資料庫Query操作。所以QueryRow總是會返回一條non-nil操作。對於錯誤查詢或者查詢所返回的實際結果為空白時,只有Row結構體(對象)的Scan方法被調用時才能體現。
Example:
id := 123var username stringerr := db.QueryRow("SELECT username FROM users WHERE id=?", id).Scan(&username)switch {case err == sql.ErrNoRows: log.Printf("No user with that ID.")case err != nil: log.Fatal(err)default: fmt.Printf("Username is %s\n", username)}
func (*DB) SetConnMaxLifetime
func (db *DB)SetConnMaxLifetime(d time.Duration)
SetConnMaxLifetime用於設定串連可被重新使用的最大時間間隔。如果逾時,則串連會在重新使用前被關閉。如果 d <= 0, 則串連將被持續保留。
func (*DB) SetMaxIdleConns
func (db *DB)SetMaxIdleConns(n int)
SetMaxIdleConns設定idle connection pool的最大串連數。如果MaxOpenConns的值 > 0,但是小於這裡設定的MaxIdleConns,則MaxIdleConns將自動降到與MaxOpenConns的限制相同。
如果 <= 0, 則沒有空閑串連會被保留。
func (*DB) SetMaxOpenConns
func (db *DB)SetMaxOpenConns(n int)
SetMaxOpenConns用於設定Database最大可以開啟的串連數。
如果 <= 0, 則沒有串連限制。且預設值為0(無限制)
func (*DB)Stats
func (db *DB)Stats() DBStats
Stats函數返回資料庫的統計資訊。
type DBStats struct { OpenConnections int}
Type Row
type Row struct{}
Row 資料結構只有一個方法Scan
func (r *Row)Scan(dst ...interface{})
Scan將匹配行中的列拷貝到dest所指向的values中。如果有多行匹配,則只返回第一行並丟棄多餘的行。如果沒有行匹配,則返回**ErrNoRows。dst中的values個數必須與返回的行的列數相同。
Scan將從database中讀取的列轉換為如下所列的Go的普通類型和sql package提供的特殊類型。
- *string
- *[]byte
- *int, *int8, *int16, *int32, *int64
- *uint, *uint8, *uint16, *uint32, *uint64
- *bool
- *float32, *float64
- *interface{}
- *RawBytes
最簡單的case是:如果從資料庫讀取的來源資料是interger,bool或string類型等,用T標識該類型,則目標正好是指向T的指標*T ,則scan簡單的通過指標將資料分配到目標變數。
Scan同樣可以在sting和numeric類型資料間無損轉換。Scan直接將從資料庫擷取的numeric類型資料字串化(stringify)為string。相反,如果將string轉化為numeric類型則需要檢查是否溢出等。同理不同類型的numeric之間轉換也需要考慮精度問題。*有一個例外就是:如果將scan得到的float64數值字串化為字串可能會丟失部分資訊。所以通常情況下,將float類型數值轉換為float64類型。
如果目標資料類型為*[]byte, Scan將從資料庫讀取的來源資料拷貝到目標地址的對於位置。Copy的副本有調用者擁有,可以被修改,且可以被無限期持有。使用類型*RawBytes可以避免拷貝操作。
如果參數的類型為*interface{},Scan將直接拷貝驅動返回的資料而不做任何的轉換。
如果源類型是time.Time,可以被Scan轉換為*time.Time, *interface{}, *string或*[]byte類型。轉換為*string或*[]byte時,將會使用到time.Format3339Nano
源類型是bool,可以被Scan轉換為*bool, *interface{}, *string, *[]byte或*RawBytes
如果要將來源資料Scan到*bool類型,則需要中繼資料是true,false,1,0或者可以被strconv.ParseBool解析的string
Type Rows
Rows結構體類似於type Row,Row是返回單行的Query結果,Rows說多行的Query結果。
type Rows struct {}
func (*Rows)Close
func (rs *Rows)Close() error
Close將關閉一個Rows,防止仍然能夠對Rows繼續進行枚舉。如果Next的返回結果是false,Rows將被自動關閉,關閉依然能夠滿足對結果的錯誤檢查。Close是idempotent的,不會影響對結果的錯誤檢查。
func (*Rows)Columns
func (rs *Rows)Columns()([]string, error)
Column返回列的名字列表。如果Rows已經被Close,則返回error。
func (*Rows)Err
func (rs *Rows)Err() error
如果在枚舉過程中有Error,Err將返回error。Err可以在顯示的或隱式的Close Rows後被調用。
func (*Rows) Next
func (rs *Rows)Next() bool
Next為Scan函數準備下一條結果,如果還有結果則返回true。沒有下一行或在準備過程中發生了錯誤則返回false,Err能夠將這兩種錯誤區分開來。
每次調用Scan擷取結果前都需要首先執行Next。
func (*Rows) Scan
Rows的Scan同Row的Scan,參考func (*Row)Scan
Type Stmt
Stmt是一個準備狀態。Stmt提供一些方法將準備狀態執行。Stmt可以安全的被多個goroutine並發執行。
type Stmt struct {}
Stmt提供如下方法:
func (s *stmt)Close() errfunc (s *stmt)Exec(args ...interface{})(Result, error)func (s *stmt)Query(args ...interface{}) (*Rows, error)func (s *stmt)QueryRow(args ...interface{}) (*Row, error)
Stmt有調用func (*DB)Prepare返回,所以如下兩個方式等效:
stmt,err := db.Prepare(querystring)res, err := stmt.Exec(...)
等效於:
res, err := db.Exec(querystring, ...)
舉一反三,其他方法也是一樣。
Tyte Tx
type Tx struct{}
Tx是進行中的資料庫事務。一次資料庫事務必須以Commit或Rollback結束。調用Commit或Rollback後,如果事務失敗則會返回錯誤ErrTxDone。
所以事務由func (*DB)Begin()返回Transaction *Tx開始,以Tx的Commit或Rollback結束。需要注意的是:有Tx的Prepare方法返回的statement也只是有Commit或Rollback關閉,而不是Stmt的Close方法關閉。
func (*Tx) Prepare
func (tx \*Tx)Prepare(query string) (\*stmt, error)
類似於DB的Prepare,Prepare為當前事務建立一個準備好的statement。當事務的的Commit或Rollback被調用後,這個statement將不在有效。
func (*Tx) Commit
func (tx *Tx)Commit() error
Commit提交當前事務。
func (*Tx) Exec
func (tx *Tx)Exec(query string, args ...interface{}) (Result, error)
Exec執行不返回結果的Query,如Insert,Update等。
func (*Tx) Query
func (tx *Tx)Query(query string, args ...interface{}) (*Rows, error)
同前面DB和Stmt的Query
func (*Tx)QueryRow
func (tx *Tx)QueryRow(query string, args ...interface{}) *Row
同DB和Stmt的Query
func (*Tx)Rollback
func (tx *Tx)Rollback() error
Rollback丟棄當前事務的操作。
func (*Tx)Stmt(stmt *stmt) *Stmt
Stmt根據一個已經存在的Stmt返回一個針對當前事務的特定Stmt。
如:
updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")...tx, err := db.Begin()...res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
上面樣本根據statement updateMoney通過Tx.Stmt得到了針對當前事務tx的相同statement。新得到的特殊statement將在tx的Commit或Rollback執行後失效。
參考連結
https://golang.org/src/database/sql/doc.txt
https://godoc.org/database/sql
https://golang.org/src/database/sql/
https://godoc.org/github.com/lib/pq
https://github.com/lib/pq
https://godoc.org/github.com/lib/pq
http://jmoiron.github.io/sqlx/
https://github.com/jmoiron/sqlx/blob/master/sqlx.go
https://github.com/golang/go/wiki/SQLInterface
https://github.com/golang/go/wiki/SQLDrivers