database
一 Go的数据库接口
1.1 接口介绍
Go官方没有提供数据库驱动,而是为开发数据库驱动定义了一些标准接口,开发者可以根据定义的接口来开发相应的数据库驱动,这样做的好处是:框架迁移极其方便。
Go数据库标准包位于以下两个包中:
- database/sql:提供了保证SQL或类SQL数据库的泛用接口
- database/sql/driver:定义了应被数据库驱动实现的接口,这些接口会被sql包使用
1.2 sql.Register
sql.Register位于database/sql,用来注册数据库驱动当第三方开发者开发数据库驱动时,都会实现init函数,在init里面会调用这个Register(name string, driver driver.Driver)
完成本驱动的注册。
我们来看一下mysql、sqlite3的驱动里面都是怎么调用的:
//https://github.com/mattn/go-sqlite3驱动
func init() {
sql.Register("sqlite3", &SQLiteDriver{})
}
//https://github.com/mikespook/mymysql驱动
// Driver automatically registered in database/sql
var d = Driver{proto: "tcp", raddr: "127.0.0.1:3306"}
func init() {
Register("SET NAMES utf8")
sql.Register("mymysql", &d)
}
我们看到第三方数据库驱动都是通过调用这个函数来注册自己的数据库驱动名称以及相应的driver实现。在database/sql内部通过一个map来存储用户定义的相应驱动。
var drivers = make(map[string]driver.Driver)
drivers[name] = driver
因此通过database/sql的注册函数可以同时注册多个数据库驱动,只要不重复。
在我们使用database/sql接口和第三方库的时候经常看到如下:
import ( "database/sql" _ "github.com/mattn/go-sqlite3" )
新手都会被这个
_
所迷惑,其实这个就是Go设计的巧妙之处,我们在变量赋值的时候经常看到这个符号,它是用来忽略变量赋值的占位符,那么包引入用到这个符号也是相似的作用,这儿使用_
的意思是引入后面的包名而不直接使用这个包中定义的函数,变量等资源。
我们在2.3节流程和函数一节中介绍过init函数的初始化过程,包在引入的时候会自动调用包的init函数以完成对包的初始化。因此,我们引入上面的数据库驱动包之后会自动去调用init函数,然后在init函数里面注册这个数据库驱动,这样我们就可以在接下来的代码中直接使用这个数据库驱动了。
1.3 driver.Driver
Driver是一个数据库驱动的接口,他定义了一个method: Open(name string),这个方法返回一个数据库的Conn接口。
type Driver interface {
Open(name string) (Conn, error)
}
返回的Conn只能用来进行一次goroutine的操作,也就是说不能把这个Conn应用于Go的多个goroutine里面。如下代码会出现错误
...
go goroutineA (Conn) //执行查询操作
go goroutineB (Conn) //执行插入操作
...