Format and remove 05.1.md spaces

This commit is contained in:
vCaesar
2017-06-10 11:51:08 +08:00
parent 86a47f4714
commit f7390e5824

View File

@@ -7,25 +7,25 @@ Go与PHP不同的地方是Go官方没有提供数据库驱动而是为开发
我们来看一下mymysql、sqlite3的驱动里面都是怎么调用的
```Go
//https://github.com/mattn/go-sqlite3驱动
func init() {
sql.Register("sqlite3", &SQLiteDriver{})
}
//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)
}
//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来存储用户定义的相应驱动。
```Go
var drivers = make(map[string]driver.Driver)
var drivers = make(map[string]driver.Driver)
drivers[name] = driver
drivers[name] = driver
```
因此通过database/sql的注册函数可以同时注册多个数据库驱动只要不重复。
@@ -44,17 +44,17 @@ Go与PHP不同的地方是Go官方没有提供数据库驱动而是为开发
Driver是一个数据库驱动的接口他定义了一个method Open(name string)这个方法返回一个数据库的Conn接口。
```Go
type Driver interface {
Open(name string) (Conn, error)
}
type Driver interface {
Open(name string) (Conn, error)
}
```
返回的Conn只能用来进行一次goroutine的操作也就是说不能把这个Conn应用于Go的多个goroutine里面。如下代码会出现错误
```Go
...
go goroutineA (Conn) //执行查询操作
go goroutineB (Conn) //执行插入操作
...
...
go goroutineA (Conn) //执行查询操作
go goroutineB (Conn) //执行插入操作
...
```
上面这样的代码可能会使Go不知道某个操作究竟是由哪个goroutine发起的,从而导致数据混乱比如可能会把goroutineA里面执行的查询操作的结果返回给goroutineB从而使B错误地把此结果当成自己执行的插入数据。
@@ -64,11 +64,11 @@ Driver是一个数据库驱动的接口他定义了一个method Open(name
Conn是一个数据库连接的接口定义他定义了一系列方法这个Conn只能应用在一个goroutine里面不能使用在多个goroutine里面详情请参考上面的说明。
```Go
type Conn interface {
Prepare(query string) (Stmt, error)
Close() error
Begin() (Tx, error)
}
type Conn interface {
Prepare(query string) (Stmt, error)
Close() error
Begin() (Tx, error)
}
```
Prepare函数返回与当前连接相关的执行Sql语句的准备状态可以进行查询、删除等操作。
@@ -80,12 +80,12 @@ Begin函数返回一个代表事务处理的Tx通过它你可以进行查询,
Stmt是一种准备好的状态和Conn相关联而且只能应用于一个goroutine中不能应用于多个goroutine。
```Go
type Stmt interface {
Close() error
NumInput() int
Exec(args []Value) (Result, error)
Query(args []Value) (Rows, error)
}
type Stmt interface {
Close() error
NumInput() int
Exec(args []Value) (Result, error)
Query(args []Value) (Rows, error)
}
```
Close函数关闭当前的链接状态但是如果当前正在执行queryquery还是有效返回rows数据。
@@ -100,10 +100,10 @@ Query函数执行Prepare准备好的sql传入需要的参数执行select操
事务处理一般就两个过程,递交或者回滚。数据库驱动里面也只需要实现这两个函数就可以
```Go
type Tx interface {
Commit() error
Rollback() error
}
type Tx interface {
Commit() error
Rollback() error
}
```
这两个函数一个用来递交一个事务,一个用来回滚事务。
@@ -111,9 +111,9 @@ Query函数执行Prepare准备好的sql传入需要的参数执行select操
这是一个Conn可选择实现的接口
```Go
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
```
如果这个接口没有定义那么在调用DB.Exec,就会首先调用Prepare返回Stmt然后执行Stmt的Exec然后关闭Stmt。
@@ -121,10 +121,10 @@ Query函数执行Prepare准备好的sql传入需要的参数执行select操
这个是执行Update/Insert等操作返回的结果接口定义
```Go
type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}
type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}
```
LastInsertId函数返回由数据库执行插入操作得到的自增ID号。
@@ -134,11 +134,11 @@ RowsAffected函数返回query操作影响的数据条目数。
Rows是执行查询返回的结果集接口定义
```Go
type Rows interface {
Columns() []string
Close() error
Next(dest []Value) error
}
type Rows interface {
Columns() []string
Close() error
Next(dest []Value) error
}
```
Columns函数返回查询数据库表的字段信息这个返回的slice和sql查询的字段一一对应而不是返回整个表的所有字段。
@@ -151,35 +151,35 @@ Next函数用来返回下一条数据把数据赋值给dest。dest里面的
RowsAffected其实就是一个int64的别名但是他实现了Result接口用来底层实现Result的表示方式
```Go
type RowsAffected int64
type RowsAffected int64
func (RowsAffected) LastInsertId() (int64, error)
func (RowsAffected) LastInsertId() (int64, error)
func (v RowsAffected) RowsAffected() (int64, error)
func (v RowsAffected) RowsAffected() (int64, error)
```
## driver.Value
Value其实就是一个空接口他可以容纳任何的数据
```Go
type Value interface{}
type Value interface{}
```
drive的Value是驱动必须能够操作的ValueValue要么是nil要么是下面的任意一种
```Go
int64
float64
bool
[]byte
string [*]除了Rows.Next返回的不能是string.
time.Time
int64
float64
bool
[]byte
string [*]除了Rows.Next返回的不能是string.
time.Time
```
## driver.ValueConverter
ValueConverter接口定义了如何把一个普通的值转化成driver.Value的接口
```Go
type ValueConverter interface {
ConvertValue(v interface{}) (Value, error)
}
type ValueConverter interface {
ConvertValue(v interface{}) (Value, error)
}
```
在开发的数据库驱动包里面实现这个接口的函数在很多地方会使用到这个ValueConverter有很多好处
@@ -191,9 +191,9 @@ ValueConverter接口定义了如何把一个普通的值转化成driver.Value的
Valuer接口定义了返回一个driver.Value的方式
```Go
type Valuer interface {
Value() (Value, error)
}
type Valuer interface {
Value() (Value, error)
}
```
很多类型都实现了这个Value方法用来自身与driver.Value的转化。
@@ -203,13 +203,13 @@ Valuer接口定义了返回一个driver.Value的方式
database/sql在database/sql/driver提供的接口基础上定义了一些更高阶的方法用以简化数据库操作,同时内部还建议性地实现一个conn pool。
```Go
type DB struct {
driver driver.Driver
dsn string
mu sync.Mutex // protects freeConn and closed
freeConn []driver.Conn
closed bool
}
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直接拿出来用就是了如果不大于0则创建一个conn,然后再返回之。