驱动

github.com/go-sql-driver/mysql

请求一个连接的函数有好几种,执行完毕处理连接的方式稍有差别,大致如下:

  • db.Ping() 调用完毕后会马上把连接返回给连接池。

  • db.Exec() 调用完毕后会马上把连接返回给连接池,但是它返回的Result对象还保留这连接的引用,当后面的代码需要处理结果集的时候连接将会被重用。

  • db.Query() 调用完毕后会将连接传递给sql.Rows类型,当然后者迭代完毕或者显示的调用.Clonse()方法后,连接将会被释放回到连接池。

  • db.QueryRow()调用完毕后会将连接传递给sql.Row类型,当.Scan()方法调用之后把连接释放回到连接池。

  • db.Begin() 调用完毕后将连接传递给sql.Tx类型对象,当.Commit()或.Rollback()方法调用后释放连接。

    连接DB

    sql.Open的第一个参数是driver名称,第二个参数是driver连接数据库的信息,各个driver可能不同。DB不是连接,并且只有当需要使用时才会创建连接,如果想立即验证连接,需要用Ping()方法,如下:

    err = db.Ping()if err != nil {
       // do something here
    }

    sql.DB的设计就是用来作为长连接使用的。不要频繁Open, Close。比较好的做法是,为每个不同的datastore建一个DB对象,保持这些对象Open。如果需要短连接,那么把DB作为参数传入function,而不要在function中Open, Close。

    读取DB

    如果方法包含Query,那么这个方法是用于查询并返回rows的。其他情况应该用Exec()

    var (
       id int
       name string
    )
    rows, err := db.Query("select id, name from users where id = ?", 1)if err != nil {
       log.Fatal(err)
    }
    defer rows.Close()for rows.Next() {
       err := rows.Scan(&id, &name)
       if err != nil {
           log.Fatal(err)
       }
       log.Println(id, name)
    }
    err = rows.Err()if err != nil {
       log.Fatal(err)
    }

    上面代码的过程为:db.Query()表示向数据库发送一个query,defer rows.Close()非常重要,遍历rows使用rows.Next(), 把遍历到的数据存入变量使用rows.Scan(), 遍历完成后检查error。有几点需要注意:

    1. 检查遍历是否有error

    2. 结果集(rows)未关闭前,底层的连接处于繁忙状态。当遍历读到最后一条记录时,会发生一个内部EOF错误,自动调用rows.Close(),但是如果提前退出循环,rows不会关闭,连接不会回到连接池中,连接也不会关闭。所以手动关闭非常重要。rows.Close()可以多次调用,是无害操作。

    单行Query

    err在Scan后才产生,所以可以如下写:

    var name stringerr = db.QueryRow("select name from users where id = ?", 1).Scan(&name)if err != nil {
       log.Fatal(err)
    }
    fmt.Println(name)

    修改数据,事务

    一般用Prepare()和Exec()完成INSERTUPDATEDELETE操作。

    事务

    db.Begin()开始事务,Commit() 或 Rollback()关闭事务。Tx从连接池中取出一个连接,在关闭之前都是使用这个连接。Tx不能和DB层的BEGINCOMMIT混合使用。

    如果你需要通过多条语句修改连接状态,你必须使用Tx,例如:

    • 创建仅对单个连接可见的临时表

    • 设置变量,例如SET @var := somevalue

    • 改变连接选项,例如字符集,超时

    处理Error

    循环Rows的Error

    如果循环中发生错误会自动运行rows.Close(),用rows.Err()接收这个错误,Close方法可以多次调用。循环之后判断error是非常必要的。

    关闭Resultsets时的error

    如果你在rows遍历结束之前退出循环,必须手动关闭

关于连接池

  1. 当需要连接,且连接池中没有可用连接时,新的连接就会被创建。

  2. 默认没有连接上限,这可能会导致数据库产生错误“too many connections”

  3. db.SetMaxIdleConns(N)设置最大空闲连接数

  4. db.SetMaxOpenConns(N)设置最大打开连接数

  5. 长时间保持空闲连接可能会导致db timeout

补充:

2、数据库

2.1、type DB struct{}

DB是一个数据库句柄,代表一个具有零到多个底层连接的连接池。

它可以安全的被多个go程同时使用。

连接池的大小可以用SetMaxIdleConns方法控制。

2.2、常用方法

(1)func Open(driverName, dataSourceName string) (*DB, error)

打开数据库,返回数据库句柄,DB可以安全的被多个go程同时使用,并会维护自身的闲置连接池。

Open函数只需调用一次,很少需要关闭DB。

(2)func (db *DB) Driver() driver.Driver

返回数据库下层驱动。

(3)func (db *DB) Ping() error

检查与数据库的连接是否仍有效,如果需要会创建连接。

(4)func (db *DB) Close() error

关闭数据库,释放任何打开的资源。

一般不会关闭DB,因为DB句柄通常被多个go程共享,并长期活跃。

(5)func (db *DB) SetMaxOpenConns(n int)

设置与数据库建立连接的最大数目。

如果n大于0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。

如果n <= 0,不会限制最大开启连接数,默认为0(无限制)。

(6)func (db *DB) SetMaxIdleConns(n int)

设置连接池中的最大闲置连接数。

如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。

如果n <= 0,不会保留闲置连接。

(7)func (db *DB) Exec(query string, args ...interface{}) (Result, error)

执行一次命令(包括查询、删除、更新、插入等),不返回任何执行结果。

参数args表示query中的占位参数。

(8)func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

执行一次查询,返回多行结果(即Rows),一般用于执行select命令。

(9)func (db *DB) QueryRow(query string, args ...interface{}) *Row

执行一次查询,并期望返回最多一行结果(即Row)。

总是返回非nil的值,直到返回值的Scan方法被调用时,才会返回被延迟的错误。

(10)func (db *DB) Prepare(query string) (*Stmt, error)

创建一个准备好的状态用于之后的查询和命令。

返回值可以同时执行多个查询和命令。

(11)func (db *DB) Begin() (*Tx, error)

开始一个事务。

隔离水平由数据库驱动决定。

3、数据表

3.1、type Rows{}

Rows是查询的结果。

它的游标指向结果集的第零行,使用Next方法来遍历各行结果。

3.2、常用方法

(1)func (rs *Rows) Columns() ([]string, error)

返回列名。

如果Rows已经关闭会返回错误。

(2)func (rs *Rows) Scan(dest ...interface{}) error

Scan将当前行各列结果填充进dest指定的各个值中。

如果某个参数的类型为*[]byte,Scan会保存对应数据的拷贝,该拷贝为调用者所有,可以安全的,修改或无限期的保存。

如果参数类型为*RawBytes可以避免拷贝;参见RawBytes的文档获取其使用的约束。

如果某个参数的类型为*interface{},Scan会不做转换的拷贝底层驱动提供的值。

如果值的类型为[]byte,会进行数据的拷贝,调用者可以安全使用该值。

(3)func (rs *Rows) Next() bool

Next准备用于Scan方法的下一行结果。

如果成功会返回真,如果没有下一行或者出现错误会返回假。

每一次调用Scan方法,甚至包括第一次调用该方法,都必须在前面先调用Next方法。

(4)func (rs *Rows) Close() error

关闭Rows,阻止对其更多的列举。

如果Next方法返回假,Rows会自动关闭。

检查Err方法结果的条件。

Close方法是幂等的(多次调用无效的成功),不影响Err方法的结果。

(5)func (rs *Rows) Err() error

Err返回可能的、在迭代时出现的错误。

Err需在显式或隐式调用Close方法后调用。

4、数据行

4.1、type Row{}

QueryRow方法返回Row,代表单行查询结果。

4.2、常用方法

(1)func (r *Row) Scan(dest ...interface{}) error

Scan将该行查询结果各列分别保存进dest参数指定的值中。

如果该查询匹配多行,Scan会使用第一行结果并丢弃其余各行。

如果没有匹配查询的行,Scan会返回ErrNoRows。

5、SQL命令状态

5.1、type Stmt struct{}

Stmt是准备好的状态。

Stmt可以安全的被多个go程同时使用。

5.2、常用方法

(1)func (s *Stmt) Exec(args ...interface{}) (Result, error)

使用提供的参数执行准备好的命令状态,返回Result类型的该状态执行结果的总结。

(2)func (s *Stmt) Query(args ...interface{}) (*Rows, error)

使用提供的参数执行准备好的查询状态,返回Rows类型查询结果。

(3)func (s *Stmt) QueryRow(args ...interface{}) *Row

使用提供的参数执行准备好的查询状态。

如果在执行时遇到了错误,该错误会被延迟,直到返回值的Scan方法被调用时才释放。

返回值总是非nil的。

如果没有查询到结果,*Row类型返回值的Scan方法会返回ErrNoRows;否则,Scan方法会扫描结果第一行并丢弃其余行。

(4)func (s *Stmt) Close() error

关闭状态。

6、事务

6.1、type Tx struct{}

Tx代表一个进行中的数据库事务。

一次事务必须以对Commit或Rollback的调用结束。

调用Commit或Rollback后,所有对事务的操作都会失败并返回错误值ErrTxDone。

6.2、常用方法

(1)func (tx *Tx) Exec(query string, args ...interface{}) (Result, error)

执行命令,但不返回结果。例如执行insert和update。

(2)func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error)

执行查询并返回零到多行结果(Rows),一般执行select命令。

(3)func (tx *Tx) QueryRow(query string, args ...interface{}) *Row

执行查询并期望返回最多一行结果(Row)。

总是返回非nil的结果,查询失败的错误会延迟到在调用该结果的Scan方法时释放。

(4)func (tx *Tx) Prepare(query string) (*Stmt, error)

准备一个专用于该事务的状态。

返回的该事务专属状态操作在Tx递交会回滚后不能再使用。

(5)func (tx *Tx) Stmt(stmt *Stmt) *Stmt

使用已存在的状态生成一个该事务特定的状态。

(6)func (tx *Tx) Commit() error

提交事务。

(7)func (tx *Tx) Rollback() error

回滚事务。

Golang中database/sql包的更多相关文章

  1. 关于Golang中database/sql包的学习

    go-sql-driver 请求一个连接的函数有好几种,执行完毕处理连接的方式稍有差别,大致如下: db.Ping() 调用完毕后会马上把连接返回给连接池. db.Exec() 调用完毕后会马上把连接 ...

  2. 在Golang中如何正确地使用database/sql包访问数据库

    本文记录了我在实际工作中关于数据库操作上一些小经验,也是新手入门golang时我认为一定会碰到问题,没有什么高大上的东西,所以希望能抛砖引玉,也算是对这个问题的一次总结. 其实我也是一个新手,机缘巧合 ...

  3. golang——database/sql包学习

    1.database/sql包 sql包提供了保证SQL或类SQL数据库的泛用接口. 使用sql包时必须注入(至少)一个数据库驱动. (1)获取mysql driver:go get -v githu ...

  4. golang中的reflect包用法

    最近在写一个自动生成api文档的功能,用到了reflect包来给结构体赋值,给空数组新增一个元素,这样只要定义一个input结构体和一个output的结构体,并填写一些相关tag信息,就能使用程序来生 ...

  5. golang中container/list包源码分析

    golang源码包中container/list实际上是一个双向链表 提供链表的一些基本操作,下面就结合定义和接口进行下说明 1. 定义 // Element is an element of a l ...

  6. golang中container/heap包源码分析

    学习golang难免需要分析源码包中一些实现,下面就来说说container/heap包的源码 heap的实现使用到了小根堆,下面先对堆做个简单说明 1. 堆概念 堆是一种经过排序的完全二叉树,其中任 ...

  7. golang中的rpc包用法

    RPC,即 Remote Procedure Call(远程过程调用),说得通俗一点就是:调用远程计算机上的服务,就像调用本地服务一样. 我所在公司的项目是采用基于Restful的微服务架构,随着微服 ...

  8. golang中的context包

    标准库的context包 从设计角度上来讲, golang的context包提供了一种父routine对子routine的管理功能. 我的这种理解虽然和网上各种文章中讲的不太一样, 但我认为基本上还是 ...

  9. golang中net/http包的简单使用

    一.介绍 http包提供了http客户端和服务端的实现 Get,Head,Post和PostForm函数发出http.https的请求 程序在使用完回复后必须关闭回复的主体 #简单的访问网站,由于没有 ...

随机推荐

  1. Filter 中注入失败问题

    参考: https://www.cnblogs.com/digdeep/p/4770004.html?tvd https://www.cnblogs.com/EasonJim/p/7666009.ht ...

  2. 【AUTO Uninstaller - 使用教程】Autodesk系列软件终极完美修复卸载工具【转载】

    小伙伴是不是遇到 CAD/3dmax/maya/Revit/Inventor 安装失败或者安装不了的问题了呢?AUTODESK系列软件着实令人头疼,CAD/3dmax/maya/Revit/Inven ...

  3. 史上最全Java面试题全集

    2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是错误的,于是我花了半个月时间对 ...

  4. 吴裕雄--天生自然 R语言开发学习:基本图形

    #---------------------------------------------------------------# # R in Action (2nd ed): Chapter 6 ...

  5. docker实践-安装wordpress

    很多人都有搭建wordpress的经历,可能被某些环境的配置搞得焦头乱耳的,这里使用docker,可以很轻松的进行wordpress的搭建工作. 安装 Docker sudo apt-get inst ...

  6. Django中加载static无法成功的解决方法

    我试着进入/admin/ 结果它的/static/ 能够正常找到目标文件…真是日了哈*奇了. 我的link标签href=/static/…. 并没有什么问题 试着在urls中加入下面代码,但是没什么用 ...

  7. 在dataframe添加1行(首行,或者尾部),且不覆盖

    如果直接用下面的代码添加第1行,则会覆盖掉原来的第1行. #指定位置增加一行: df.loc[0]={'a':1,'b':2} 正确方法: 新建一个同样的 dataframe, 然后合并两个dataf ...

  8. 数据分析交互工具jupyter notebook需要密码登陆解决办法

    想要做数据分析,交互可视化工具jupyter notebook是必不可少的,但是在安装和使用其时候总是会出现各种各样的问题,本文针对notebook启动需要密码的问题进行解决. 首先看一下启动jupy ...

  9. Git学习小结 ~ Lethe's Blog

    学习自https://www.liaoxuefeng.com/wiki/896043488029600 一.创建版本库 (1) git init 初始化一个Git仓库 (2)添加文件到Git仓库,分两 ...

  10. 陪诊App,陪孝子找回人性

    2015年开始,越来越多的陪诊App开始上线,纷纷迎来了自己的第一批用户,同时,也迎来了大量资本的青睐,有些名气的问诊app甚至能单轮获得超过1000万元的融资,事实上,投资者是否青睐,简直就是中国新 ...