分享
  1. 首页
  2. 文章

Golang Package-database/sql

吃一堑消化不良 · · 4155 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一、导入库

import (
 "database/sql"
 _ "github.com/lib/pq"
)

二、连接DB

func main() {
 db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full")
 /*db, err := sql.Open("postgres", 
 "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full")*/
 if err != nil {
 log.Fatal(err)
 }
 defer db.Close()
}

sql.Open的第一个参数是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。

在database/sql中有一个很基本的连接池,当需要连接,且连接池中没有可用连接时,新的连接就会被创建;如果长时间保持空闲连接,可能会导致db timeout。可以设置SetMaxIdleConns和SetMaxOpenConns,也就是最大空闲连接和最大连接数,分别是下面这两个函数:

db.SetMaxIdleConns(n)
db.SetMaxOpenConns(n)

三、查询DB

(1)一般查询Query

var name, sex string
rows, err := db.Query("select name, sex from user where id = 1ドル ", 1)
if err != nil {
	fmt.Println(err)
}
defer rows.Close()
for rows.Next() {
	err := rows.Scan(&name, &sex)
	if err != nil {
		fmt.Println(err)
	}
}
err = rows.Err()
if err != nil {
	fmt.Println(err)
}
fmt.Println("name:", name, "sex:", sex)

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

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

(2)单条查询QueryRow

var name string
err = db.QueryRow("select name from user where id = 1ドル", 222).Scan(&name)
if err != nil {
 if err == sql.ErrNoRows {
 // there were no rows, but otherwise no error occurred
 } else {
 log.Fatal(err)
 }
}
fmt.Println(name)

四、增删改Exec

Prepared Statements and Connection
在数据库层面,Prepared Statements是和单个数据库连接绑定的。客户端发送一个有占位符的statement到服务端,服务器返回一个statement ID,然后客户端发送ID和参数来执行statement。

在GO中,连接不直接暴露,你不能为连接绑定statement,而是只能为DB或Tx绑定。database/sql包有自动重试等功能。当你生成一个Prepared Statement

(1)自动在连接池中绑定到一个空闲连接
(2)Stmt对象记住绑定了哪个连接
(3)执行Stmt时,尝试使用该连接。如果不可用,例如连接被关闭或繁忙中,会自动re-prepare,绑定到另一个连接。
这就导致在高并发的场景,过度使用statement可能导致statement泄漏,statement持续重复prepare和re-prepare的过程,甚至会达到服务器端statement数量上限。

有些场景不适合用statement:

(1)数据库不支持。例如Sphinx,MemSQL。他们支持MySQL wire protocol, 但不支持"binary" protocol。
(2)statement不需要重用很多次,并且有其他方法保证安全。

stmt, err := db.Prepare("insert into user(name, sex)values(1,ドル2ドル)")
if err != nil {
	fmt.Println(err)
}
rs, err := stmt.Exec("go-test", 12)
if err != nil {
	fmt.Println(err)
}
//可以获得影响行数
affect, err := rs.RowsAffected()
fmt.Println("affect ", affect ," rows")

五、事务

tx, err := db.Begin()
if err != nil {
 log.Fatal(err)
}
defer tx.Rollback()
stmt, err := tx.Prepare("INSERT INTO foo VALUES (1ドル)")
if err != nil {
 log.Fatal(err)
}
for i := 0; i < 10; i++ {
 _, err = stmt.Exec(i)
 if err != nil {
 log.Fatal(err)
 }
}
err = tx.Commit()
if err != nil {
 log.Fatal(err)
}
defer stmt.Close() //runs here!

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


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:吃一堑消化不良

查看原文:Golang Package-database/sql

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
4155 次点击 ∙ 1 赞
上一篇:Golang 结构体
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏