From 6b5ce8a17564e56937ddd9753fbf33f690093b47 Mon Sep 17 00:00:00 2001 From: xiemengjun Date: Mon, 10 Sep 2012 23:19:56 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=BA=94=E7=AB=A0=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 5.1.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 6 deletions(-) diff --git a/5.1.md b/5.1.md index dc6a8911..8e5dae32 100644 --- a/5.1.md +++ b/5.1.md @@ -68,25 +68,123 @@ Stmt是一种准备好的状态,和Conn相关联,而且是只能应用于一 Query(args []Value) (Rows, error) } +Close函数关闭当前的链接状态,但是如果当前正在执行query,query还是有效返回raws数据。 + +NumInput函数返回当前预留参数的个数,当返回>=0时数据库驱动就会智能检查调用者的参数。当数据库驱动包不知道预留参数的时候,返回-1。 + +Exec函数执行Prepare准备好的sql,传入参数执行update/insert等操作,返回Result数据 + +Query函数执行Prepare准备好的sql,传入需要的参数执行select操作,返回Rows结果集 ##drive.Tx 事务处理一般就两个过程,递交或者回滚。数据库驱动里面也只需要实现这两个函数就可以 type Tx interface { - Commit() error + Commit() error Rollback() error } + +这两个函数一个用来递交一个事务,一个用来回滚事务。 -##drive.Execer +##drive.Execer +这个接口是Conn可选的可实现可不实现的接口 + + type Execer interface { + Exec(query string, args []Value) (Result, error) + } + +如果这个接口没有定义,那么在调用DB.Exec,就会首先调用Prepare返回Stmt,然后执行Stmt的Exec,然后关闭Stmt。 -##drive.Result +##drive.Result +这个是执行Update/Insert等操作返回的结果接口定义 + + type Result interface { + LastInsertId() (int64, error) + RowsAffected() (int64, error) + } + +LastInsertId函数返回插入数据库之后返回自动增长字段的ID,Insert之后返回的数据 +RowsAffected函数返回通过query影响的数据库条数。 -##drive.Rows +##drive.Rows +Rows是执行查询返回的结果集接口定义 + + type Rows interface { + + Columns() []string + + Close() error + + Next(dest []Value) error + } + +Columns函数返回查询数据库表的字段信息,这个返回的slice和你sql查询的字段一一对应,而不是返回整个表的所有字段。 + +Close函数用来关闭Rows迭代器。 + +Next函数用来返回下一条数据,把数据赋值给dest。dest里面的元素必须是drive.Value的值除了string,所有的string必须转换成[]byte.如果最后没数据了,Next函数最后返回io.EOF。 -##drive.RowsAffected -##drive.Value +##drive.RowsAffected +RowsAffested其实就是一个int64的别名,但是他实现了Result接口,用来底层实现Result的表示方式 + + type RowsAffected int64 + + func (RowsAffected) LastInsertId() (int64, error) + + func (v RowsAffected) RowsAffected() (int64, error) + +##drive.Value +Value其实就是一个空接口,他可以容纳任何的数据 + + type Value interface{} + +Value的值必须所有的驱动里面控制的,Value要么是nil,要么是下面的任意一种 + + int64 + float64 + bool + []byte + string [*]除了Rows.Next返回的不能是string. + time.Time + +##drive.ValueConverter +ValueConverter接口定义了如何把一个普通的值转化成drive.Value的接口 + + type ValueConverter interface { + ConvertValue(v interface{}) (Value, error) + } + +ValueConverter对于各种各种的值的实现必须保持高度的一致性,在驱动包里面很多地方会使用到这个转化接口 + +- 转化drive.value到数据库表相应的字段,例如int64的数据如何转化成数据库表uint16字段 +- 把数据库查询结果转化成drive.Value值 +- 在scan函数里面如何吧dirve.Value值转化成用户定义的值 + +##drive.Valuer +Valuer接口定义了返回如何返回一个drive.Value值 + + type Valuer interface { + Value() (Value, error) + } +很多类型上面都定义了这个Value方法,用来实现每个相应类型如何转化为drive.Value类型。 + +通过上面的讲解,对于驱动的开发有了细致的了解,一个驱动基本上就是实现上面的这些接口就能完成我们平常的增删改所有的操作了,底层就是和相应的数据库进行数据交互就可以了。 + +##database/sql +database/sql里面定义了基于这个驱动之上的一些方法,这些方法都是基于drive接口来封装的,同时内部还实现了一个建议的conn pool。 + + type DB struct { + driver driver.Driver + dsn string + mu sync.Mutex // protects freeConn and closed + freeConn []driver.Conn + closed bool + } + +我们可以看到Open函数返回的是DB对象,里面有一个freeConn,这个就是那个简易的连接池。它的实现也是就是很简单,当执行Db.prepare的时候最后会defer:`db.putConn(ci, err)`,也就是放入连接池,而每次调用conn的时候也会优先判断freeConn的长度是否大于0,大于0说明有使用过的conn,直接拿出来就用了。 + ## links * [目录]()