go标准库的学习-database/sql/driver

参考:https://studygolang.com/pkgdocgolang

1》导入方式:sql

import "database/sql/driver"

driver包定义了应被数据库驱动实现的接口,这些接口会被sql包使用。 数据库

绝大多数代码应使用sql包。缓存

 

2》driver.Driver - 在database/sql/driver中函数

Driver是一个数据库驱动的接口,其定义了一个Open(name string)方法,该方法返回一个数据库的Conn接口:ui

type Driver interface { // Open返回一个新的与数据库的链接,参数name的格式是驱动特定的。 // // Open可能返回一个缓存的链接(以前关闭的链接),但这么作是没必要要的; // sql包会维护闲置链接池以便有效的重用链接。 // // 返回的链接同一时间只会被一个go程使用。 Open(name string) (Conn, error) }

由于返回的链接同一时间只会被一个go程使用,因此返回的Conn只能用来进行一次goroutine操做,即不能把这个Conn应用于Go的多个goroutine中,不然会出现错误,如:
spa

go goroutineA(Conn) //执行查询操做 go goroutineB(Conn) //执行插入操做

这样的代码会使Go不知某个操做究竟是由哪一个goroutine发起的从而致使数据混乱。便可能会讲goroutineA里面执行的查询操做的结果返回给goroutineB,从而让goroutineB将此结果当成本身执行的插入数据
code

 

 

3》driver.Conn - 在database/sql/driver中blog

Conn是一个数据链接的接口定义。这个Conn只能应用在一个goroutine中,如上所说。接口

type Conn interface { // Prepare返回一个准备好的、绑定到该链接的状态。 Prepare(query string) (Stmt, error) // Close做废并中止任何如今准备好的状态和事务,将该链接标注为再也不使用。 // // 由于sql包维护着一个链接池,只有当闲置链接过剩时才会调用Close方法, // 驱动的实现中不须要添加本身的链接缓存池。  Close() error // Begin开始并返回一个新的事务。  Begin() (Tx, error) }

Prepare函数返回与当前链接相关的SQL语句的准备状态,能够进行查询、删除等操做

Close函数关闭当前的链接,执行释放链接拥有的资源等清理工做。由于驱动实现了database/sql中建议的conn pool,因此不用再去实现缓存conn之类的,这样会更容易引发问题

Begin函数返回一个表明事务处理的Tx,经过它你能够进行查询、更新等操做,或者对事务进行回滚、递交

 

4》driver.Stmt - 在database/sql/driver中

Stmt是一种准备好的状态,绑定到一个Conn中,并只能应用在一个goroutine中。

type Stmt interface { // Close关闭Stmt。 // // 和Go1.1同样,若是Stmt被任何查询使用中的话,将不会被关闭。  Close() error // NumInput返回占位参数的个数。 // // 若是NumInput返回值 >= 0,sql包会提早检查调用者提供的参数个数, // 而且会在调用Exec或Query方法前返回数目不对的错误。 // // NumInput能够返回-1,若是驱动占位参数的数量不知时。 // 此时sql包不会提早检查参数个数。 NumInput() int // Exec执行查询,而不会返回结果,如insert或update。  Exec(args []Value) (Result, error) // Query执行查询并返回结果,如select。  Query(args []Value) (Rows, error) }

Close函数关闭当前的链接状态,可是若是当前正在执行query,query仍是会有效地返回rows数据

Exec函数执行Conn的Prepare准备好的sql,传入参数执行update/insert等操做,返回Result数据

Query函数执行Conn的Prepare准备好的sql,传入须要的参数执行select操做,返回Rows结果集

 

5》driver.Tx - 在database/sql/driver中

事务处理通常就两个过程,递交或回滚,即下面的两个函数:

type Tx interface { Commit() error Rollback() error }

 

6》driver.Execer - 在database/sql/driver中

这是一个Conn可选择实现的接口

type Execer interface { Exec(query string, args []Value) (Result, error) }

若是一个Conn未实现Execer接口,sql包的DB.Exec会首先准备一个查询(即调用Prepare返回Stmt),执行状态(即执行Stmt的Exec函数),而后关闭状态(即关闭Stmt)。Exec可能会返回ErrSkip。

 

7》driver.Result

这是是执行Update/insert等操做返回的结果接口定义

type Result interface { // LastInsertId返回insert等命令后数据库自动生成的ID  LastInsertId() (int64, error) // RowsAffected返回被查询影响的行数  RowsAffected() (int64, error) }

 

8》driver.Rows

Rows是执行查询返回的结果集接口定义

type Rows interface { // Columns返回各列的名称,列的数量能够从切片长度肯定。 // 若是某个列的名称未知,对应的条目应为空字符串。 Columns() []string // Close关闭Rows。  Close() error // 调用Next方法以将下一行数据填充进提供的切片中,即返回下一条数据,并把数据返回给dest。 // 提供的切片必须和Columns返回的切片长度相同。 // // 切片dest可能被填充同一种驱动Value类型,但字符串除外;即dest里面的元素必须是driver.Vlaue的值,除了string。 // 全部string值都必须转换为[]byte。 // // 当没有更多行时,Next应返回io.EOF。  Next(dest []Value) error }

Columns函数返回查询数据库表的字段信息,返回的slice和sql查询的字段一一对应,而不是返回整个表的全部字段

 

9》driver.RowsAffected

type RowsAffected int64

RowsAffected其实就是int64的别名,可是它实现了Result接口,用来底层实现Result的表示方式

RowsAffected实现了Result接口,用于insert或update操做,这些操做会修改零到多行数据。

func (RowsAffected) LastInsertId

func (RowsAffected) LastInsertId() (int64, error)

func (RowsAffected) RowsAffected

func (v RowsAffected) RowsAffected() (int64, error)


10》driver.Value

type Value interface{}

Value其实就是一个空接口,它能够容纳任何数据

driver.Value是驱动必须可以操做的Value,因此Value要么是nil,要么是下面的任意一种:

int64
float64
bool []byte string [*] Rows.Next不会返回该类型值 time.Time

 

11》driver.ValueConverter

ValueConverter接口定义了一个如何把一个普通值转化成driver.Value的接口

type ValueConverter interface { // ConvertValue将一个值转换为驱动支持的Value类型 ConvertValue(v interface{}) (Value, error) }

ValueConverter接口提供了ConvertValue方法。

driver包提供了各类ValueConverter接口的实现,以保证不一样驱动之间的实现和转换的一致性。ValueConverter接口有以下用途:

  • 转换sql包提供的driver.Value类型值到数据库指定列的类型,并保证它的匹配,例如保证某个int64值知足一个表的uint16列。
  • 转换数据库提供的值(即数据库查询结果)成driver.Value类型。
  • 在Scan函数中被sql包用于将driver.Value类型转换为用户定义的类型。

 

12》driver.Valuer

type Valuer interface { // Value返回一个驱动支持的Value类型值  Value() (Value, error) }

Valuer接口定义了一个返回driver.Value的方法

不少类型都实现了这个Value方法,用来实现自身与driver.Value的转换

 

13》ColumnConverter

type ColumnConverter

type ColumnConverter interface {
    // ColumnConverter返回指定列的ValueConverter
    // 若是该列未指定类型,或不该特殊处理,应返回DefaultValueConverter
    ColumnConverter(idx int) ValueConverter
}

若是Stmt有本身的列类型,能够实现ColumnConverter接口,返回值能够将任意类型转换为驱动的Value类型。

 

14》变量

1.Bool

var Bool boolType

Bool是ValueConverter接口值,用于将输入的值转换为布尔类型。使用方式为driver.Bool(1),会返回true

转换规则以下:

- 布尔类型:不作修改
- 整数类型:
     1 为真
     0 为假
     其他整数会致使错误
- 字符串和[]byte:与strconv.ParseBool的规则相同
- 全部其余类型都会致使错误

其实现源码为:

var Bool boolType

type boolType struct{}

var _ ValueConverter = boolType{}

func (boolType) String() string { return "Bool" }

func (boolType) ConvertValue(src interface{}) (Value, error) {
    switch s := src.(type) { //首先查看输入的src值的类型
    case bool: //若是输入的是bool类型,则直接输出便可
        return s, nil
    case string: //若是是其余类型,则要将其转成Bool类型
        b, err := strconv.ParseBool(s)
        if err != nil {
            return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
        }
        return b, nil
    case []byte:
        b, err := strconv.ParseBool(string(s))
        if err != nil {
            return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
        }
        return b, nil
    }

    //除了上面的几种类型,若是是下面的类型,只有当其值为1或0时可以将其转成bool类型
    sv := reflect.ValueOf(src)
    switch sv.Kind() {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        iv := sv.Int()
        if iv == 1 || iv == 0 {
            return iv == 1, nil
        }
        return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv)
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
        uv := sv.Uint()
        if uv == 1 || uv == 0 {
            return uv == 1, nil
        }
        return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv)
    }
    //除了上面的类型,若是输入的src是其余的类型,则会报错
    return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src)
}

 

2.Int32

var Int32 int32Type

Int32是一个ValueConverter接口值,用于将值转换为int64类型,会尊重int32类型的限制。

3.String

var String stringType

String是一个ValueConverter接口值,用于将值转换为字符串。若是值v是字符串或者[]byte类型,不会作修改,若是值v是其它类型,会转换为fmt.Sprintf("%v", v)。

4.DefaultParameterConverter

var DefaultParameterConverter defaultConverter

DefaultParameterConverter是ValueConverter接口的默认实现,当一个Stmt没有实现ColumnConverter时,就会使用它。 

若是值value知足函数IsValue(value)为真,DefaultParameterConverter直接返回 value。不然,整数类型会被转换为int64,浮点数转换为float64,字符串转换为[]byte。其它类型会致使错误。

5.ResultNoRows

var ResultNoRows noRows

ResultNoRows是预约义的Result类型值,用于当一个DDL命令(如create table)成功时被驱动返回。它的LastInsertId和RowsAffected方法都返回错误

举例:

package main 
import(
    "fmt"
    "reflect"
    "time"
    "database/sql/driver"
)

type valueConverterTest struct {
    c   driver.ValueConverter
    in  interface{}
    out interface{}
    err string
}

var now = time.Now()
var answer int64 = 42

type (
    i  int64
    f  float64
    b  bool
    bs []byte
    s  string
    t  time.Time
    is []int
)

var valueConverterTests = []valueConverterTest{
    {driver.Bool, "true", true, ""},
    {driver.Bool, "True", true, ""},
    {driver.Bool, []byte("t"), true, ""},
    {driver.Bool, true, true, ""},
    {driver.Bool, "1", true, ""},
    {driver.Bool, 1, true, ""},
    {driver.Bool, int64(1), true, ""},
    {driver.Bool, uint16(1), true, ""},
    {driver.Bool, "false", false, ""},
    {driver.Bool, false, false, ""},
    {driver.Bool, "0", false, ""},
    {driver.Bool, 0, false, ""},
    {driver.Bool, int64(0), false, ""},
    {driver.Bool, uint16(0), false, ""},
    {c: driver.Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
    {c: driver.Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"},
    {driver.DefaultParameterConverter, now, now, ""},
    {driver.DefaultParameterConverter, (*int64)(nil), nil, ""},
    {driver.DefaultParameterConverter, &answer, answer, ""},
    {driver.DefaultParameterConverter, &now, now, ""},
    {driver.DefaultParameterConverter, i(9), int64(9), ""},
    {driver.DefaultParameterConverter, f(0.1), float64(0.1), ""},
    {driver.DefaultParameterConverter, b(true), true, ""},
    {driver.DefaultParameterConverter, bs{1}, []byte{1}, ""},
    {driver.DefaultParameterConverter, s("a"), "a", ""},
    {driver.DefaultParameterConverter, is{1}, nil, "unsupported type main.is, a slice of int"},
}



func main() {
    for i, tt := range valueConverterTests {
        out, err := tt.c.ConvertValue(tt.in)
        goterr := ""
        if err != nil {
            goterr = err.Error()
        }
        if goterr != tt.err {
            fmt.Printf("test %d: %T(%T(%v)) error = %q; want error = %q\n",
                i, tt.c, tt.in, tt.in, goterr, tt.err)
        }
        if tt.err != "" {
            continue
        }
        if !reflect.DeepEqual(out, tt.out) {
            fmt.Printf("test %d: %T(%T(%v)) = %v (%T); want %v (%T)\n",
                i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out)
        }
    }
}

 

6.错误ErrBadConn

var ErrBadConn = errors.New("driver: bad connection")

ErrBadConn应被驱动返回,以通知sql包一个driver.Conn处于损坏状态(如服务端以前关闭了链接),sql包会重启一个新的链接。

为了不重复的操做,若是数据库服务端执行了操做,就不该返回ErrBadConn。即便服务端返回了一个错误。

7.错误ErrSkip

var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")

ErrSkip可能会被某些可选接口的方法返回,用于在运行时代表快速方法不可用,sql包应像未实现该接口的状况同样执行。ErrSkip只有文档显式说明的地方才支持,如driver.Execer。

 

15》其余函数

func IsValue

func IsValue(v interface{}) bool

IsValue报告v是不是合法的Value类型参数。和IsScanValue不一样,IsValue接受字符串类型。

func IsScanValue

func IsScanValue(v interface{}) bool

IsScanValue报告v是不是合法的Value扫描类型参数。和IsValue不一样,IsScanValue不接受字符串类型。

相关文章
相关标签/搜索