doc: 阅读golang-sqlx文档
This commit is contained in:
@@ -147,6 +147,93 @@ err = rows.Err()
|
|||||||
|
|
||||||
> 在使用`Rows`时,如果并不迭代完整个结果集,请确保调用`rows.Close()`方法将连接返回到连接池中。
|
> 在使用`Rows`时,如果并不迭代完整个结果集,请确保调用`rows.Close()`方法将连接返回到连接池中。
|
||||||
|
|
||||||
|
#### Query errors
|
||||||
|
其中,`Query`方返回的error可能是`在服务端进行prepare操作或execute操作时发生的任何异常`,该异常的可能场景如下:
|
||||||
|
- 从连接池中获取了bad connection
|
||||||
|
- 因sql语法、类型不匹配、不正确的field name或table name导致的错误
|
||||||
|
|
||||||
|
在大多数场景下,`Rows.Scan`会复制其从driver获取的数据,因为`Rows.Scan`并无法感知driver对缓冲区进行reuse的方式。类型`sql.RawBytes`可以被用于获取` zero-copy slice of bytes from the actual data returned by the driver`。在下一次调用`Next`方法时,该值将会无效,因为该bytes的内存空间将会被driver重写。
|
||||||
|
|
||||||
|
#### Connection Closed Scenes
|
||||||
|
在调用完`Query`方法后,connection将会等到如下两种场景才会关闭:
|
||||||
|
- Rows中所有的行都通过`Next`方法调用被迭代
|
||||||
|
- rows中所有行未被完全迭代,但是`rows.Close()`方法被调用
|
||||||
|
|
||||||
|
#### Queryx
|
||||||
|
sqlx拓展的`Queryx`方法,其行为和`Query`方法一致,但是实际返回的是`sqlx.Rows`类型,`sqlx.Rows`类型对scan行为进行了拓展:
|
||||||
|
```go
|
||||||
|
type Place struct {
|
||||||
|
Country string
|
||||||
|
City sql.NullString
|
||||||
|
TelephoneCode int `db:"telcode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := db.Queryx("SELECT * FROM place")
|
||||||
|
for rows.Next() {
|
||||||
|
var p Place
|
||||||
|
err = rows.StructScan(&p)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`sqlx.Rows`的主要拓展是支持`StructScan()`,其会自动将结果扫描到struct fields中。
|
||||||
|
> 注意,在使用struct scan时,struct field必须被exported(首字母大写)。
|
||||||
|
|
||||||
|
可以使用`db` struct tag指定field映射到哪个column。默认情况下,会对field name使用`strings.Lower`并和column name相匹配。
|
||||||
|
|
||||||
|
#### QueryRow
|
||||||
|
QueryRow会从server端拉取一行数据。其从connection pool中获取一个连接,并且通过Query执行该查询,并返回一个`Row` object,`Row object`内部包含了`Rows`对象
|
||||||
|
```go
|
||||||
|
row := db.QueryRow("SELECT * FROM place WHERE telcode=?", 852)
|
||||||
|
var telcode int
|
||||||
|
err = row.Scan(&telcode)
|
||||||
|
```
|
||||||
|
|
||||||
|
和Query不同的是,QueryRow并不会返回error,故而,可以对返回结果链式嵌套其他方法调用,例如`Scan`。
|
||||||
|
|
||||||
|
如果在执行`QueryRow`查询时报错,那么该error将会被`Scan`方法返回,如果并没有查询到rows,那么Scan方法将会返回`sql.ErrNoRows`。
|
||||||
|
|
||||||
|
如果Scan操作失败了(例如类型不匹配),error也会被Scan方法返回。
|
||||||
|
|
||||||
|
Row对象内部的`Rows`结构在Scan后就会关闭,`即代表QueryRow使用的连接持续打开,直到Result被扫描后才会关闭`。
|
||||||
|
|
||||||
|
#### QueryRowx
|
||||||
|
`QueryRowx`拓展将会返回一个sqlx.Row`,其实现了和`sqlx.Rows`相同的拓展,示例如下
|
||||||
|
```go
|
||||||
|
var p Place
|
||||||
|
err := db.QueryRowx("SELECT city, telcode FROM place LIMIT 1").StructScan(&p)
|
||||||
|
```
|
||||||
|
#### Get & Select
|
||||||
|
Get/Select和`QueryRow`/`Query`类似,但是其能够节省代码编写,并能提供灵活的扫描语义。
|
||||||
|
|
||||||
|
##### scannable
|
||||||
|
scannable定义如下:
|
||||||
|
- 如果value并不是struct,那么该value是scannable的
|
||||||
|
- 如果value实现了sql.Scanner,那么该value是scannable的
|
||||||
|
- 如果struct没有exported field,那么其是scannble的
|
||||||
|
|
||||||
|
Get和Select对于scannable类型使用了`rows.Scan`方法,对non-scannable类型使用`rows.StructScan`方法,使用示例如下:
|
||||||
|
```go
|
||||||
|
p := Place{}
|
||||||
|
pp := []Place{}
|
||||||
|
|
||||||
|
// this will pull the first place directly into p
|
||||||
|
err = db.Get(&p, "SELECT * FROM place LIMIT 1")
|
||||||
|
|
||||||
|
// this will pull places with telcode > 50 into the slice pp
|
||||||
|
err = db.Select(&pp, "SELECT * FROM place WHERE telcode > ?", 50)
|
||||||
|
|
||||||
|
// they work with regular types as well
|
||||||
|
var id int
|
||||||
|
err = db.Get(&id, "SELECT count(*) FROM place")
|
||||||
|
|
||||||
|
// fetch at most 10 place names
|
||||||
|
var names []string
|
||||||
|
err = db.Select(&names, "SELECT name FROM place LIMIT 10")
|
||||||
|
```
|
||||||
|
|
||||||
|
`Get`和`Select`都会对Rows进行关闭,并且在执行遇到错误时会返回error。
|
||||||
|
|
||||||
|
> 但是,需要注意的是,Select会将整个result set都导入到内存中。如果结果集较大,最好使用传统的`Queryx`/`StructScan`迭代方式。
|
||||||
|
|
||||||
### Exec和Query在归还连接池上的差异
|
### Exec和Query在归还连接池上的差异
|
||||||
Exec操作和Query操作在归还连接到连接池的时机有所不同:
|
Exec操作和Query操作在归还连接到连接池的时机有所不同:
|
||||||
- `Exec`: `Exec`方法在`server返回执行结果给client之后`,`client根据返回结果构建并返回sql.Result之前`,将会将连接返回给连接池
|
- `Exec`: `Exec`方法在`server返回执行结果给client之后`,`client根据返回结果构建并返回sql.Result之前`,将会将连接返回给连接池
|
||||||
|
|||||||
Reference in New Issue
Block a user