一, database/sql 接口
Go 语言官方没有提供数据库驱动, 而是为开发数据库驱动定义了标准接口 database/sql, 开发者可以根据 database/sql 接口来开发相应的数据库驱动, 只要是按照标准接口 database/sql 开发的代码, 以后需要迁移数据库时, 不需要任何修改.
二, database/sql 常用接口
1,sql.Register
sql.Register 函数用来注册数据库驱动, 第三方开发者开发数据库驱动时, 会在 init 函数内调用 sql.Register 完成本驱动的注册.
- 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)
- 2,driver.Driver
Driver 是一个数据库驱动的接口, 定义了一个 Open(name string) 方法, 返回一个数据库的 Conn 接口.
- type Driver interface {
- Open(name string) (Conn, error)
- }
Conn 只能用来进行一次 goroutine 操作, 即 Conn 应用于多个 goroutine.
第三方驱动都会实现 driver.Driver 接口, Open 方法会解析 name 参数来获取相关数据库的连接信息, 解析完成后, 使用此连接信息来初始化一个 Conn 并返回.
3,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 可以进行查询, 更新等操作或者对事务进行回滚, 递交.
4,driver.Stmt
driver.Stmt 是一种准备好的状态, 与 Conn 相关联, 而且只能应用于一个 goroutine 中, 不能应用于多个 goroutine.
- 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 结果集
5,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
- }
- 6,driver.Execer
driver.Execer 是一个 Conn 可选择实现的接口.
- type Execer interface {
- Exec(query string, args []Value) (Result, error)
- }
如果第三方数据库驱动没有实现 driver.Execer 接口, 调用 DB.Exec 会首先调用 Prepare 返回 Stmt, 然后执行 Stmt 的 Exec, 然后关闭 Stmt.
7,driver.Result
driver.Result 是执行 Update/Insert 等操作返回的结果接口.
- type Result interface {
- LastInsertId() (int64, error)
- RowsAffected() (int64, error)
- }
LastInsertId 函数返回由数据库执行插入操作得到的自增 ID 号.
RowsAffected 函数返回 query 操作影响的数据条目数.
8,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.
9,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
- }
- 10,driver.Value
driver.Value 是空接口, 是数据库驱动必须能够操作的 Value,Value 可以是 nil,int64,float64,bool,[]bytestring,time.Time.
- type Value interface{
- }
- 11,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 值转化成用户定义的值
12,driver.Valuer
driver.Valuer 接口定义一个返回 driver.Value 的方法.
- type Valuer interface {
- // Value returns a driver Value.
- Value() (Value, error)
- }
- 13,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, 然后返回.
来源: http://www.bubuko.com/infodetail-2928558.html