database/sql
Golang提供了标准库database/sql
用于和数据库交互,database/sql只是一套统一地抽象接口,真正与数据库打交道的是各个数据库对应的驱动实现,因此使用前需要先注册对应数据库的驱动(github.com/go-sql-driver/mysql
),然后就可以使用SQL中定义的接口来统一地操作数据库了。
连接池sql.DB
import (
"fmt"
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func ConnectMysql() *sql.DB {
mysqlUrl := "用户名:密码@(地址:端口)/数据库名称"
db, _ := sql.Open("mysql", mysqlUrl)
defer db.Close()
err := db.Ping()
if err != nil{
fmt.Println("mysql连接失败,错误日志为:", err.Error())
return nil
}else{
// Do something here
}
return db
}
- sql.DB刚开始建立时是懒加载的,不会自动创建新的连接,只有使用Ping()或者运行查询时才会自动生成一个新的连接然后去连接数据库,只有这个时候才能确定数据库是否真的OK,所以建议一定要在sql.Open后运行Ping()确定数据连接正常运行。
- sql.DB是连接后初始化的一个连接池,通常全局就初始化这一个连接池,并且长期运行,所有后续数据库操作都使用该连接池进行。sql.DB内部自动维护连接池,当需要连接时自动选择一个空闲的连接,如果没有空闲就建立一个新的连接,当连接不再使用时放回连接池中,内部会自动管理空闲回收。
- 数据库的连接是一个比较大的耗时和资源消耗操作,首选需要经典的TCP三次握手,tcp连接后数据库需要分配连接资源,同时根据连接信息鉴权等,所以建议使用长连接。对应到我们的go中,sql.DB会自动管理连接池,最好全局使用一个连接池,不要重复的open或者close。
查询
sql.DB支持4种查询:
db.Query()
db.QueryRow()
db.Prepare(sql) stmt.Query(args)
db.Exec()
- db.Query(): 返回多行数据,需要依次遍历,并且需要自己关闭查询结果集
- db.QueryRow() :专门查询一行数据语法,返回ErrNoRow或者一行数据,不需要自己关闭结果集
- db.Prepare() :预先将一个数据库连接(con)和一个条sql语句绑定并返回stmt结构体代表这个绑定后的连接,然后运行stmt.Query()或者stmt.QueryRow();stmt是并发安全的。之所以这样设计,是因为每次直接调用db.Prepare都会自动选择一个可用的con,每次选择的可能不是同一个con
- db.Exec() :用于执行insert、update、delete等不需要返回结果集的操作
标准库sql不支持但常用的特性
- 不支持多条sql执行
- 不支持返回多个结果集
- 不支持存储过程(Mysql驱动目前不支持)
- 不支持Scan到map、struct
- 不建议uint64
第三方扩展库http://github.com/jmoiron/sqlx
便捷功能
- StructScan 、SliceScan、MapScan Get、Select MustExec
- 支持命名参数
- 支持IN查询自动展开参数
Get、Select类似于QueryRow和Query,但Get和Select可以自动将结果Scan到特定数据
Struct字段必须能导出,且根据db tag(如果没有就用小写字段名)进行匹配
参考地址:小慢哥Linux运维