diff --git a/5.1.md b/5.1.md index c4536b1f..dc6a8911 100644 --- a/5.1.md +++ b/5.1.md @@ -1,4 +1,92 @@ #5.1 database/sql接口 +Go和PHP不同的地方是,他没有官方提供数据库驱动,而是定义了一些标准接口用来开发数据库驱动,第三方用户可以根据定义的接口来开发相应的数据库驱动,其实这样做有一个好处,我们按照标准接口开发的代码,将来迁移数据库是相当方便的,换一个数据库驱动,但是底层的接口没有任何变化。那么Go都定义了那些标准接口呢?让我们来详细的分析一下 + +##sql.Register +这个函数是database/sql里面用来注册数据库驱动的,当第三方开发者开发完毕一个数据库驱动,都会在驱动里面有一个init函数,里面都会调用这个`Register(name string, driver driver.Driver)` + +我们来看一下mymysql、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设计的巧妙之处,我们知道在变量赋值的时候看到过这个,是用来忽略变量的意思,那么这个包引入也是,这个只是引入包而不直接使用这个pkg的调用,我们在2.3流程和函数里面介绍过init函数的初始化过程,包在引入的时候会去初始化包内部的init函数,那么我们引入上面的数据库驱动包之后会去调用init函数,然后在init函数里面注册了这个数据库驱动,这样我们就可以在接下来的代码中直接使用这个数据库驱动了。 + +##driver.Driver +数据库驱动是一个接口定义,他定义了一个method: Open(name string),这个方法返回一个数据库的Conn接口,这个Conn只能用来进行一次goroutine的操作。 + + type Driver interface { + Open(name string) (Conn, error) + } + +每个驱动的这个函数都是通过name参数用来解析,然后初始化一个Conn返回。 + +##driver.Conn +数据库连接是一个接口定义,他定义了一系列方法,这个Conn只能应用在一个goroutine里面,不能使用在多个goroutine里面。 + + type Conn interface { + Prepare(query string) (Stmt, error) + Close() error + Begin() (Tx, error) + } + +Prepare函数返回与当前连接相关的准备好Sql语句的状态,可以进行查询、删除等操作。 + +Close函数关闭使得当前的连接失效,以及和当前连接相关的状态、处理。因为database/sql里面实现了建议的conn pool,所以你不要再自己去实现缓存conn之类的,这样容易引起问题。 + +Begin函数返回一个事务处理Tx,可以进行事物操作,回滚、递交等操作。 + +##drive.Stmt +Stmt是一种准备好的状态,和Conn相关联,而且是只能应用于一个goroutine中,不能应用在多个goroutine中。 + + type Stmt interface { + Close() error + NumInput() int + Exec(args []Value) (Result, error) + Query(args []Value) (Rows, error) + } + + + +##drive.Tx +事务处理一般就两个过程,递交或者回滚。数据库驱动里面也只需要实现这两个函数就可以 + + type Tx interface { + Commit() error + Rollback() error + } + +##drive.Execer + +##drive.Result + +##drive.Rows + +##drive.RowsAffected + +##drive.Value ## links * [目录]()