go标准库的学习-database/sql/driver
参考:https://studygolang.com/pkgdoc
1》导入方式:
import "database/sql/driver"
driver包定义了应被数据库驱动实现的接口,这些接口会被sql包使用。
绝大多数代码应使用sql包。
2》driver.Driver - 在database/sql/driver中
Driver是一个数据库驱动的接口,其定义了一个Open(name string)方法,该方法返回一个数据库的Conn接口:
type Driver interface {
// Open返回一个新的与数据库的连接,参数name的格式是驱动特定的。
//
// Open可能返回一个缓存的连接(之前关闭的连接),但这么做是不必要的;
// sql包会维护闲置连接池以便有效的重用连接。
//
// 返回的连接同一时间只会被一个go程使用。
Open(name string) (Conn, error)
}
因为返回的连接同一时间只会被一个go程使用,所以返回的Conn只能用来进行一次goroutine操作,即不能把这个Conn应用于Go的多个goroutine中,否则会出现错误,如:
go goroutineA(Conn) //执行查询操作
go goroutineB(Conn) //执行插入操作
这样的代码会使Go不知某个操作到底是由哪个goroutine发起的从而导致数据混乱。即可能会讲goroutineA里面执行的查询操作的结果返回给goroutineB,从而让goroutineB将此结果当成自己执行的插入数据
3》driver.Conn - 在database/sql/driver中
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
转换规则如下:
- 布尔类型:不做修改
- 整数类型:
为真
为假
其余整数会导致错误
- 字符串和[]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 == || iv == {
return iv == , 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 == || uv == {
return uv == , 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 = 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, "", true, ""},
{driver.Bool, , true, ""},
{driver.Bool, int64(), true, ""},
{driver.Bool, uint16(), true, ""},
{driver.Bool, "false", false, ""},
{driver.Bool, false, false, ""},
{driver.Bool, "", false, ""},
{driver.Bool, , false, ""},
{driver.Bool, int64(), false, ""},
{driver.Bool, uint16(), false, ""},
{c: driver.Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"},
{c: driver.Bool, in: , 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(), int64(), ""},
{driver.DefaultParameterConverter, f(0.1), float64(0.1), ""},
{driver.DefaultParameterConverter, b(true), true, ""},
{driver.DefaultParameterConverter, bs{}, []byte{}, ""},
{driver.DefaultParameterConverter, s("a"), "a", ""},
{driver.DefaultParameterConverter, is{}, 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不接受字符串类型。
go标准库的学习-database/sql/driver的更多相关文章
- go标准库的学习-database/sql
参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...
- go标准库的学习-net/http
参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...
- go标准库的学习-crypto/md5
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...
- go标准库的学习-crypto/sha1
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...
- go标准库的学习-crypto/sha256
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...
- python 标准库基础学习之开发工具部分1学习
#2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...
- python calendar标准库基础学习
# -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...
- 《C标准库》学习笔记整理
简介 <C标准库>书中对 C 标准库中的 15 个头文件的内容进行了详细的介绍,包括各头文件设计的背景知识.头文件中的内容.头文件中定义的函数和变量的使用.实现.测试等. 我学习此书的目的 ...
- python linecache标准库基础学习
#python标准库基础之:linecacge:高效读取文本文件#说明与作用"""可以从文件或者导入python模块获取文件,维护一个结果缓存,从而可以更高效地从相同文件 ...
随机推荐
- mysql查看执行sql语句的记录日志
开启日志模式 -- 1.设置 -- SET GLOBAL log_output = 'TABLE';SET GLOBAL general_log = 'ON'; //日志开启 -- SET GLOB ...
- C# 单例模式和窗体的单例打开方法
第一种最简单,但没有考虑线程安全,在多线程时可能会出问题,不过俺从没看过出错的现象,表鄙视我…… public class Singleton{ private static Singleton ...
- blfs(systemd版本)学习笔记-配置远程访问和管理lfs系统
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 要实现远程管理和配置lfs系统需要配置以下软件包: 前几页章节脚本的配置:https://www.cnblogs.com/ren ...
- python中收集函数的解包问题
收集参数的解包问题 - 把参数放入list或者字典中,直接把list/dict中的值放入收集参数中- 语法:参照案例 # 收集参数的问题 def stu(*args): print("=&q ...
- vue-cli脚手架目录一览
最近在学习vue,看的稀里糊涂.今天从头开始,把cli配置的vue项目目录和配置文件搞清楚. 先看看整个项目目录结构: 再看看build文件夹下相关文件及目录: config文件夹下目录和文件: 接下 ...
- ionic 项目中,ng-bind-html会过滤掉内嵌样式的问题
一.引入$sce,转化一步即可 $scope.articlesdetail.info = $sce.trustAsHtml($scope.articlesdetail.info); 参考网址: htt ...
- Docker 加速器设置
在部署完docker的时候我们需要进行在镜像源下载镜像的时候有时候会出现特别慢的情况(这是因为本地到源的网络出现了问题),这时候就需要使用加速器来对镜像进行下载了,在面咱们就聊一聊docker加速器的 ...
- Flutter 依赖的那些事儿
Flutter 里面有2种库一样的东西, Package -creating a pure Dart component. like a new Widget. 这种是纯Dart,相当于你自己写的组件 ...
- Python 会是我们的未来吗?
Python 热度激增 根据 Stack Overflow 的一项调查显示,Python 不仅在专业领域的使用率得到增长,在普通开发上的使用率也有所提升,有 40% 的受访者表示他们现在正在使用 Py ...
- Scala学习笔记2 (带着问题学习, 逐渐扩展。理解吃透scala.)
问题: 把 文本字符串"[1, 2, 3, 4, 5]" 转换成一个数组. 答案: val x = "[1, 2, 3, 4, 5]" val y =x sli ...