Golang官方没有提供数据库驱动,只是为开发数据库驱动定义了一些标准接口,开发者可以根据官方定义的标准接口来开发相应的数据库驱动。这样做的好处是:只要是按照标准接口开发的代码,需要迁移数据库时不需要任何的修改。 Golang通过package database/sql定义了这一系列的针对SQL(或SQL-like)数据库的通用接口。sql package必须与一个database driver结合使用。SQL database drivers列表可以参考SQL Drivers。
sql和sql/driver的设计目标
sql package主要由两部分组成,database/sql和database/sql/driver。sql和sql/driver的设计目标是:
- 为SQL或SQL-Like的数据库提供的通用数据库API。当前已经有的Go libraries包括SQLite,MYSQL和Postgres等,但是所有的都具有非常不同的感觉,而且感觉不太像Go的风格。
- 感觉像Go
- 更多的考虑常见的情况。通常情况下SQL应当可移植。SQL的边界情况或者特定数据库的扩展可以被应用检查到,并有条件的使用。不应该将非常特殊的一些数据库扩展或奇怪的使用方法放入作为目的。
将database driver的基本实现(sql/driver interfaces的实现)与所有用户层类型和方法的实现分离。
简而言之,就是:
User Code —> sql package (具体类型) —> sql/driver (接口) —> Database Driver —> sql(注册的数据库) + sql/driver(implement interface)- 让类型转换(casting/conversions)在所有驱动间一致。为了达到这个目的,大部分的转换在sql package中完成,而不是在各个driver中,drivers只处理一小部分的数据类型。
- 灵活的类型转换,但是需要承受silent的截断和其他精度损失。
- 很好的处理并发。用户不需要关心数据库每个连接线程的安全问题,同样不需要为连接维护free pool。’db’ package将根据需要处理bookkeeping。给定一个 *sql.DB,它应该是能够被多个协程间共享的,不需要任何额外的同步。
- 对于Push complexity,向下放到sql+driver packages是必要的,而不是直接暴露给用户。否则,sql package需要暴露一个不过分讲究如何访问的理想数据库,尽管这样是不对的。
- 在sql/driver中提供一些可选的interfaces供drivers实现用于一些特殊情况或fastpaths。但是只有sql package知道这些。对于用户代码就是有些东西可能启动或启动得稍微快一点。
database/sql/driver定义的接口
driver.Driver
driver.Driver是一个interface类型,Driver只定义了一个方法Open,Open返回一个数据库的Conn interface。
type Driver interface {
Open(name string)(Conn, error)
}
返回的Conn一次只能被一个goroutine使用,因为如果一个Conn同时被多个goroutine使用,Go无法判断某个操作由哪个goroutine发起,可能会造成数据混乱。
数据库driver都会实现Open这个函数,用于解析参数name获取数据库相关的信息,解析完成后使用此信息来初始化一个Conn,并返回。
driver.Conn
Conn是一个数据库连接interface。Conn被认为是有状态的,它不能被多个goroutines同时使用。
Conn定义了三个方法:Prepare,Close和Begin。
type Conn interface {
Prepare(query string)(Stmt, error)
Close() error
Begin() (Tx, error)
}
* Prepare返回一个绑定到当前连接的准备状态Stmt;
* Close停止当前连接的transtraction并关闭当前连接,并将其标记为不再使用。另外因为sql package中维护了一个连接的free pool,并且在有过剩的空闲连接时只会调用Close。所以第三方驱动没有必要去实现自己的连接缓存(connection caching)。
* Begin启动并返回一个新的Transaction
driver.Stmt
Stmt是一个准备状态的interface,和Conn绑定,不能被多个goroutines同时使用。
type Stmt interface {
Close() error
NumInput() int
Exec(args []Value) (Result, error)
Query(args []Value) (Rows, error)
}
* Close关闭当前状态。Go1.1后,Stmt不会关闭一个正在被Queries使用的状态。
* NumInput返回预留参数的个数。如果返回值 >=0,sql package会检查调用者的参数,如果有错误则会在调用Stmt的Exec和Query方法被调用前向调用者返回错误。如果驱动不知道预留参数的个数,NumInput返回-1,这种情况下sql package不会检查Exec和Query的参数个数。
* Exec执行不会rows的数据库操作,如INSERT,UPDATE等;
* Query执行返回row的数据库操作,如SELECT等。
driver.Execer
Execer是一个可选择实现的interface,它也可可以通过Conn实现。如果Conn没有实现Execer,则SQL package的DB.Exec将首先需要准备一个query,执行statement,然后关闭statement。
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
driver.Queryer
Queryer也是一个可选择实现的interface,同样可以通过Conn实现。如果Conn没有实现Queryer,则SQL package的DB.Query首先需要准备一个Query,执行statement,然后关闭statement。
type Queryer interface {
Query(query string,args []Value) (Rows, error)
}
driver.Result
Result是Query执行的结果。
type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}
- LastInsertId返回数据库自动生成的ID,例如INSERT的primary key。
- RowsAffected返回Query操作所涉及到的行的数目。
driver.ColumnConverter
ColumnConverter也是一个可选择实现的interface。如果statement知道自己column的类型,并且可以将任何类型转换为dirver值,则ColumnConverter可以被Stmt实现。
type ColumnConverter interface {
ColumnConverter(index int) ValueConverter
}
ColumnConverter根据传入的Column index返回一个对应Column的ValueConverter, 如果不知道指定column的类型,或者该类型不能被处理,则返回一个DefaultValueConverter。
driver.Rows
Rows是一个Query执行结果的迭代器。
type Rows interface{
Columns() []string
Close() error
Next(dest []Value) error
}
- Columns返回columns的名字。columns的数目可以通过slice的length获取。如果有某个特定的column的名字无法获取,则返回一个空string。
- Close将停止rows的迭代。
- Next被调用从Query返回结果的rows中一行到提供的slice中。slice所占用的空间将与Columns()同宽。dest slice只能存放driver Value类型,但是不包括string类型。所有的string都必须被转换成[]byte。如果没有更过的行了,则返回io.EOF
driver.Value
Value是一种drivers能handle的类型。实际上它是一个空接口,可以包含任何类型。Drivers可以处理的类型是nil或者如下类型:
- int64
- float64
- bool
- []byte
- string
- time.time
参考链接
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
有疑问加站长微信联系(非本文作者)