Go語言開發(十七)、Go語言database/sql接口

Go語言開發(十七)、Go語言database/sql接口

1、database/sql接口

Go語言官方沒有提供數據庫驅動,而是爲開發數據庫驅動定義了標準接口database/sql,開發者能夠根據database/sql接口來開發相應的數據庫驅動,只要是按照標準接口database/sql開發的代碼,之後須要遷移數據庫時,不須要任何修改。mysql

2、database/sql經常使用接口

一、sql.Register

sql.Register函數用來註冊數據庫驅動,第三方開發者開發數據庫驅動時,會在init函數內調用sql.Register完成本驅動的註冊。sql

func Register(name string, driver driver.Driver) {
   driversMu.Lock()
   defer driversMu.Unlock()
   if driver == nil {
      panic("sql: Register driver is nil")
   }
   if _, dup := drivers[name]; dup {
      panic("sql: Register called twice for driver " + name)
   }
   drivers[name] = driver
}

Go-SQL-Driver/MySQL數據庫驅動的實現以下:數據庫

func init() {
   sql.Register("mysql", &MySQLDriver{})
}

第三方數據庫驅動一般經過調用sql.Register函數來註冊本身的數據庫驅動名稱以及相應的driver實現。在database/sql內部經過一個map來存儲用戶定義的相應驅動。
var drivers = make(map[string]driver.Driver)緩存

二、driver.Driver

Driver是一個數據庫驅動的接口,定義了一個Open(name string)方法,返回一個數據庫的Conn接口。session

type Driver interface {
      Open(name string) (Conn, error)
}

Conn只能用來進行一次goroutine操做,即Conn應用於多個goroutine。
第三方驅動都會實現driver.Driver接口,Open方法會解析name參數來獲取相關數據庫的鏈接信息,解析完成後,使用此鏈接信息來初始化一個Conn並返回。ide

三、driver.Conn

driver.Conn是一個數據庫鏈接的接口,定義了一系列方法,Conn只能應用在一個goroutine中,不能使用在多個goroutine中。函數

type Conn interface {
   Prepare(query string) (Stmt, error)
   Close() error
   Begin() (Tx, error)
}

Prepare函數返回與當前鏈接相關的執行Sql語句的準備狀態,能夠進行查詢、刪除等操做。
Close函數關閉當前的鏈接,執行釋放鏈接擁有的資源等清理工做。一般第三方數據庫驅動實現了database/sql建議的鏈接池,開發者沒必要去實現緩存鏈接。
Begin函數返回一個表明事務處理的Tx,經過Tx能夠進行查詢、更新等操做或者對事務進行回滾、遞交。ui

四、driver.Stmt

driver.Stmt是一種準備好的狀態,與Conn相關聯,並且只能應用於一個goroutine中,不能應用於多個goroutine。debug

type Stmt interface {
   Close() error

   NumInput() int
   Exec(args []Value) (Result, error)
   Query(args []Value) (Rows, error)
}

Close函數關閉當前的鏈接狀態,但若是當前正在執行query,query仍是有效返回rows數據。
NumInput函數返回當前預留參數的個數,當返回>=0時數據庫驅動就會智能檢查調用者的參數。當數據庫驅動包不知道預留參數的時候,返回-1。
Exec函數執行Prepare準備好的sql,傳入參數執行update/insert等操做,返回Result數據
Query函數執行Prepare準備好的sql,傳入須要的參數執行select操做,返回Rows結果集code

五、driver.Tx

driver.Tx是事務接口,包含Commit、Rollback方法,數據庫驅動只需實現Commit、Rollback函數便可。

type Tx interface {
   Commit() error
   Rollback() error
}

Go-SQL-Driver/MySQL數據庫驅動的實現以下:

type mysqlTx struct {
   mc *mysqlConn
}

func (tx *mysqlTx) Commit() (err error) {
   if tx.mc == nil || tx.mc.closed.IsSet() {
      return ErrInvalidConn
   }
   err = tx.mc.exec("COMMIT")
   tx.mc = nil
   return
}

func (tx *mysqlTx) Rollback() (err error) {
   if tx.mc == nil || tx.mc.closed.IsSet() {
      return ErrInvalidConn
   }
   err = tx.mc.exec("ROLLBACK")
   tx.mc = nil
   return
}

六、driver.Execer

driver.Execer是一個Conn可選擇實現的接口。

type Execer interface {
   Exec(query string, args []Value) (Result, error)
}

若是第三方數據庫驅動沒有實現driver.Execer接口,調用DB.Exec會首先調用Prepare返回Stmt,而後執行Stmt的Exec,而後關閉Stmt。

七、driver.Result

driver.Result是執行Update/Insert等操做返回的結果接口。

type Result interface {
   LastInsertId() (int64, error)
   RowsAffected() (int64, error)
}

LastInsertId函數返回由數據庫執行插入操做獲得的自增ID號。
RowsAffected函數返回query操做影響的數據條目數。

八、driver.Rows

driver.Rows是執行查詢返回的結果集接口。

type Rows interface {
   Columns() []string
   Close() error
   Next(dest []Value) error
}

Columns函數返回查詢數據庫表的字段信息,這個返回的slice和sql查詢的字段一一對應,而不是返回整個表的全部字段。
Close函數用來關閉Rows迭代器。
Next函數用來返回下一條數據,把數據賦值給dest。dest裏面的元素必須是driver.Value的值除了string,返回的數據裏面全部的string都必需要轉換成[]byte。若是最後沒數據了,Next函數最後返回io.EOF。

九、driver.RowsAffected

driver.RowsAffected是int64的別名,但實現了Result接口,用來底層實現Result的表示方式。

type RowsAffected int64

var _ Result = RowsAffected(0)

func (RowsAffected) LastInsertId() (int64, error) {
   return 0, errors.New("no LastInsertId available")
}

func (v RowsAffected) RowsAffected() (int64, error) {
   return int64(v), nil
}

十、driver.Value

driver.Value是空接口,是數據庫驅動必須可以操做的Value,Value能夠是nil,int64,float64,bool,[]bytestring,time.Time。
type Value interface{}

十一、driver.ValueConverter

driver.ValueConverter接口定義瞭如何把一個普通的值轉化成driver.Value的接口

type ValueConverter interface {
   // ConvertValue converts a value to a driver Value.
   ConvertValue(v interface{}) (Value, error)
}

driver.ValueConverter接口實現以下:

type stringType struct{}

func (stringType) ConvertValue(v interface{}) (Value, error) {
   switch v.(type) {
   case string, []byte:
      return v, nil
   }
   return fmt.Sprintf("%v", v), nil
}

數據庫驅動開發中,ConvertValue方法用途普遍:
(1)轉化driver.value到數據庫表相應的字段,例如int64的數據如何轉化成數據庫表uint16字段。
(2)把數據庫查詢結果轉化成driver.Value值
(3)在scan函數裏面如何把driver.Value值轉化成用戶定義的值

十二、driver.Valuer

driver.Valuer接口定義一個返回driver.Value的方法。

type Valuer interface {
   // Value returns a driver Value.
   Value() (Value, error)
}

1三、sql.Open

func Open(driverName, dataSourceName string) (*DB, error) {
   driversMu.RLock()
   driveri, ok := drivers[driverName]
   driversMu.RUnlock()
   if !ok {
      return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
   }

   if driverCtx, ok := driveri.(driver.DriverContext); ok {
      connector, err := driverCtx.OpenConnector(dataSourceName)
      if err != nil {
         return nil, err
      }
      return OpenDB(connector), nil
   }

   return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil
}

Open函數返回DB對象,

type DB struct {
   connector driver.Connector
   numClosed uint64

   mu           sync.Mutex // protects following fields
   freeConn     []*driverConn
   connRequests map[uint64]chan connRequest
   nextRequest  uint64 // Next key to use in connRequests.
   numOpen      int    // number of opened and pending open connections
   openerCh    chan struct{}
   resetterCh  chan *driverConn
   closed      bool
   dep         map[finalCloser]depSet
   lastPut     map[*driverConn]string // stacktrace of last conn's put; debug only
   maxIdle     int                    // zero means defaultMaxIdleConns; negative means 0
   maxOpen     int                    // <= 0 means unlimited
   maxLifetime time.Duration          // maximum amount of time a connection may be reused
   cleanerCh   chan struct{}

   stop func() // stop cancels the connection opener and the session resetter.
}

freeConn是簡易的鏈接池。當執行db.prepare -> db.prepareDC時會defer dc.releaseConn,而後調用db.putConn,把鏈接放入鏈接池,每次調用db.conn的時候會先判斷freeConn的長度是否大於0,大於0說明有能夠複用的conn,若是不大於0,則建立一個conn,而後返回。

相關文章
相關標籤/搜索