Go没有官方提供的数据库驱动,而是定义了一些数据库驱动标准接口,这样我们可以根据定义的接口来开发相应的数据库驱动,后期进行数据库转移时就不需要进行修改。
我们来看看Go有哪些数据库标准接口
①sql.Register
在开发数据库驱动时,都会实现init函数,然后在init函数中调用sql的Register函数完成驱动的注册。
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
}
使用init函数调用sql的Register函数完成驱动的注册示例
示例一
func init() {
sql.Register("sqlite3", &SQLiteDriver{})
}
实列二
var d = Driver{proto: "tcp", raddr: "127.0.0.1:3306"}
func init() {
Register("SET NAMES utf8")
sql.Register("mymysql", &d)
}
所有注册过的数据库驱动都会存储在一个map中
drivers = make(map[string]driver.Driver)
②driver.Driver
这也是一个数据库驱动标准接口,关于它的源码说明如下:
type Driver interface {
// Open返回与数据库的新连接。
//名称是特定于驱动程序的格式的字符串。
// Open可以返回一个缓存连接(一个先前已关闭),但这样做是不必要的; sql包维护一个空闲连接池,以便有效地重用。
//返回的连接一次只能由一个goroutine使用。
Open(name string) (Conn, error)
}
第三方驱动都会定义这个函数,它会解析name参数来获取相关数据库的连接信息,解析完成后,它将使用此信息来初始化一个Conn并返回它。
③driver.Conn
这是一个数据库连接的接口,只能应用在一个goroutine里面,不能使用在多个goroutine里面,它定义的一些方法如下所示:
// Conn是与数据库的连接。 它不是由多个goroutines同时使用的。
// Conn被认为是有状态的。
type Conn interface {
// 返回与当前连接相关的执行Sql语句的准备状态,可以进行查询、删除等操作。
Prepare(query string) (Stmt, error)
//关闭当前的连接并可能停止任何当前准备好的语句和事务,将此连接标记为不再使用。
//因为sql包维护一个空闲的连接池,并且只有在空闲连接过剩时才调用Close,所以驱动程序不需要进行自己的连接缓存。
Close() error
//返回一个代表事务处理的Tx,通过它你可以进行查询,更新等操作,或者对事务进行回滚、递交。
//不推荐使用:驱动程序应该实现ConnBeginTx(或者另外)。
Begin() (Tx, error)
}
④driver.Stmt
关于它的源码解释如下所示:
// Stmt是一个准备好的声明。 这是一个康恩而不是
//同时使用多个goroutines。
type Stmt interface {
//关闭语句。
//从Go 1.1开始,如果Stmt正在被任何查询使用,它将不会被关闭。
Close() error
// NumInput返回占位符参数的数量。
//如果NumInput返回> = 0,则在调用语句的Exec或Query方法之前,sql包将从调用者检查参数计数并将错误返回给调用者。
//如果驱动程序不知道占位符数,NumInput也可能返回-1。 在这种情况下,sql包将无法检查Exec或Query参数计数。
NumInput() int
// Exec执行不返回行的查询,例如INSERT或UPDATE。
//不推荐使用:驱动程序应该实现StmtExecContext(或另外)。
Exec(args []Value) (Result, error)
// Query执行可能返回行的查询,例如SELECT。
//不推荐使用:驱动程序应该实现StmtQueryContext(或另外)。
Query(args []Value) (Rows, error)
}
⑤driver.Tx
事务处理一般就两个过程,递交或者回滚。数据库驱动里面也只需要实现这两个函数就可以
type Tx interface {
Commit() error //递交一个事务
Rollback() error //用来回滚事务
}
⑥driver.Execer
作为Conn可选择实现的一个接口,关于它的源码解释如下所示
// Execer是一个可选的接口,可以由Conn实现。
//如果Conn既不实现ExecerContext也不实现Execer Execer,则sql包的DB.Exec将首先准备一个查询,执行该语句,然后关闭该语句。
// Exec可能会返回ErrSkip。
//不推荐使用:驱动程序应该实现ExecerContext。
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
⑦driver.Result
这个是执行Update/Insert等操作返回的结果接口定义,关于它的源码解释如下:
//Result是查询执行的结果接口。
type Result interface {
// LastInsertId返回数据库的自动生成的ID,例如,INSERT到具有主键的表中。
LastInsertId() (int64, error)
// RowsAffected返回受查询影响的行数。
RowsAffected() (int64, error)
}
⑧driver.Rows
Rows是执行查询返回的结果集接口定义,关于它的源码解释如下:
// Rows是执行查询结果的迭代器。
type Rows interface {
//返回列的名称。 从切片的长度推断结果的列数。 如果未知特定列名称,则应为该条目返回空字符串。
Columns() []string
// Close关闭行迭代器。
Close() error
//调用Next以将下一行数据填充到提供的切片中。 提供的切片与Columns()的宽度相同。
//当没有更多行时,Next应该返回io.EOF。
//不应将dest写入Next之外。 关闭行时应小心,不要修改dest中保存的缓冲区。
Next(dest []Value) error
}
⑨driver.Value
Value其实就是一个空接口,他可以容纳任何的数据
//值是驱动程序必须能够处理的值。
//它可以是nil,由数据库驱动程序的Name Value Checker接口处理的类型,或者是以下类型之一的实例:
//int64,float64,bool,[]byte,string,time.Time
type Value interface{}
⑩driver.RowsAffected
RowsAffested其实就是一个int64的别名,但是他实现了Result接口,用来底层实现Result的表示方式
// RowsAffected实现INSERT或UPDATE操作的结果,该操作会改变多个行。
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
}
11 driver.ValueConverter
ValueConverter接口定义了如何把一个普通的值转化成driver.Value的接口
// ValueConverter是提供ConvertValue方法的接口。
//驱动程序包提供了ValueConverter的各种实现,以提供驱动程序之间转换的一致实现。 ValueConverters有几个用途:
// *从sql包提供的Value类型转换为数据库表的特定列类型并确保它适合,例如确保特定的int64适合表的uint16列。
// *将数据库中给定的值转换为其中一个驱动值类型。
// *由sql包,用于从驱动程序的Value类型转换为扫描中的用户类型。
type ValueConverter interface {
// ConvertValue将值转换为驱动程序值。
ConvertValue(v interface{}) (Value, error)
}
12 driver.Valuer
Valuer接口定义了返回一个driver.Value的方式
// Valuer是提供Value方法的接口。
//实现Valuer接口的类型能够将自身转换为驱动程序值。
type Valuer interface {
// Value返回驱动程序值。
Value() (Value, error)
}
参考书籍:《Go Web编程》