19年底36周:Go database/sql库-Go数据库操作
2019-10-07 本文已影响0人
习惯研究所所长
一、简介
- database/sql提供了Go访问和操作SQL数据库的方法。
- 在Go语言中,使用sql.DB使用此类型来创建语句和事务,并执行查询以及获取结果。
- sql.DB负责的是:
- 负责通过驱动程序打开和关闭与实际底层数据库的连接;
- 负责管理连接池(但不负责回收,需要开发者自己回收);
二、数据库操作
- 数据库连接:连接仅仅是对数据库抽象,并没有真正连接。需要通过db.Ping()来测试连接。
- 不同数据库的查询语句占位符:
- Mysql:?
- Postgresql: $N,其中N为数字
- SQLite:接受上述两者之一
- Oracle::paramN
- 基本命令:
Open() – creates a DB
Close() - closes the DB
Query() - 查询
QueryRow() -查询行
Exec() -执行操作,update,insert,delete
Row - A row is not a hash map, but an abstraction of a cursor
Next()
Scan()
Prepare() - 准备语句- 数据库的基本操作逻辑:准备、执行、关闭
- 数据库的操作主要分为两个:Exec(),Query()
- 如何使用Query()
- 使用db.Query()来发送查询到数据库,获取结果集Rows,并检查错误。
- 使用rows.Next()作为循环条件,迭代读取结果集。
- 使用rows.Scan从结果集中获取一行结果。
- 使用rows.Err()在退出迭代后检查错误。
- 使用rows.Close()关闭结果集,释放连接。
func dbPrepare(db sql.DB){
stmt, err := db.Prepare("select id, name from users where id != ?")
// stmt是一个支持高并发的预备sql, 当stmt关闭后,那么后面的所有使用stmt的都不可以使用
// 准备、执行、关闭
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
rows, err := stmt.Query(1) // 1, stmt.Query() 发送查询到数据库获取结果集
if err != nil {
log.Fatal(err)
}
defer rows.Close() // 5, rows.Close() 延迟关闭结果集,释放连接
for rows.Next() { // 2, rows.Next() 循环迭代结果集
err := rows.Scan(&id, &name) // 3, rows.Scan() 读取一行数据,这个是从远程一行行读取的还是本地缓存?
processErr(err)
log.Println(id,name)
}
// 4, rows.Err() 在退出迭代后检查错误
if err = rows.Err(); err != nil {
log.Fatal(err)
}
}
- 准备语句Prepared Statement
- 一个stmt对应着一个数据库连接.
- stmt 会记住它一个最近使用过的连接,如果这个连接已经被用了,那么它会新建一个stmt和重新获取一个连接。
- 上述的方式会导致大量的高并发连接和泄漏,重连的次数超乎想象,结果就你懂得。
- 有时候纯文本查询 a plaintext query 效率可能会更好(如果一个prepared statement 能够被多次执行,那么用它。否则还是直接手写ok。
- 此外,Mysql数据库不建议使用prepared statement
- 以上原因参考:An example of this can be seen at the [图片上传失败...(image-6033f3-1570439040218)] blog.
三、使用sql.DB注意事项
- 把sql.DB视为长期存在的对象,否则可能会遇到诸如重复使用和连接共享不足;
- 使用db.Query(sqlStr, sqlDatas)和db.Prepare(sqlStr).Exec(sqlDatas)的区别:
- 答:本质上没区别?Prepare once,execute many times,对于批量操作的时候用这个?
- 增删改等doesn’t return rows的操作使用 Exec()[并且配套使用prepared statement], 查询使用 Query()。
- 答:使用Query但不读取返回结果,会导致底层连接永远无法释放。
[图片上传失败...(image-1c045c-1570439040218)]
- 查询时一定要释放连接defer rows.Close()