golang中的标准库database/sql 包为SQL和类SQL数据库的操作提供了通用的接口。
database/sql 包 必须与数据库driver 配套使用。
目前已有的SQL database drivers 见链接。
这里面就包括比较常用的MySQL driver go-sql-driver/mysql 。
database/sql 包的设计可以说是很巧妙。
它对于上层应用提供了标准的API接口,对下层驱动driver暴露了简单的驱动接口。
并且实现了连接池的管理。这意味着,不同数据库的驱动只需要实现驱动接口,不需要关心连接池的实现细节。
常用的API操作接口
连接数据库
db, err := sql.Open(driver, dataSourceName)
连接MySQL,这里driver就是"mysql".
dataSourceName 定义了具体的连接参数。
执行SQL
ExecContext 常用执行没有rows返回的场景。
例如新建、删除
result, err := db.ExecContext(ctx,
"INSERT INTO users (name, age) VALUES ($1, $2)",
"gopher",
27,
)
QueryContext 常用于查询数据集rows。
例如,查询select
rows, err := db.QueryContext(ctx, "SELECT name FROM users WHERE age = $1", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d\n", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
QueryRowContext 用于查询一条记录。
var age int64
err := db.QueryRowContext(ctx, "SELECT age FROM users WHERE name = $1", name).Scan(&age)
Prepared statements可以防止sql注入。
age := 27
stmt, err := db.PrepareContext(ctx, "SELECT name FROM users WHERE age = $1")
if err != nil {
log.Fatal(err)
}
rows, err := stmt.Query(age)
// process rows
在一个statements上,也可以执行ExecContext, QueryContext and QueryRowContext 。
statements使用完后,需要Close。
事务Transactions
可以使用以下方式开始一个事务Transactions:
tx, err := db.BeginTx(ctx, nil)
if err != nil {
log.Fatal(err)
}
在一个事务Transactions上,可以执行ExecContext, QueryContext, QueryRowContext 以及PrepareContext。
一个Transactions的结束,或者调用 Commit 或者调用 Rollback。
NULL的处理
sql.NullString 类型可用于处理字段值为NULL的情况。
如果name字段值可能为null,可以这样处理:
var name sql.NullString
err := db.QueryRowContext(ctx, "SELECT name FROM names WHERE id = $1", id).Scan(&name)
...
if name.Valid {
// use name.String
} else {
// value is NULL
}
标准库 database/sql 目前支持NullBool, NullFloat64, NullInt64, NullInt32, NullString and NullTime 。