Go Wiki:SQLInterface
简介
database/sql
软件包提供了一个围绕 SQL(或类似 SQL 的)数据库的通用接口。有关详细信息,请参阅 官方文档。
此页面提供示例用法模式。
数据库驱动程序
database/sql
软件包必须与数据库驱动程序结合使用。请参阅 https://golang.ac.cn/s/sqldrivers 以获取驱动程序列表。
以下文档假设已导入驱动程序。
连接到数据库
Open
用于创建数据库句柄
db, err := sql.Open(driver, dataSourceName)
其中 driver 指定数据库驱动程序,dataSourceName 指定特定于数据库的连接信息,例如数据库名称和身份验证凭据。
请注意,Open
不会直接打开数据库连接:这会延迟到发出查询时。要验证在发出查询之前是否可以建立连接,请使用 PingContext
方法
if err := db.PingContext(ctx); err != nil {
log.Fatal(err)
}
使用后,使用 Close
关闭数据库。
执行查询
ExecContext
用于不返回任何行的查询
result, err := db.ExecContext(ctx,
"INSERT INTO users (name, age) VALUES ($1, $2)",
"gopher",
27,
)
其中结果包含最后插入的 ID 和受影响的行数。这些值的可用性取决于数据库驱动程序。
QueryContext
用于检索
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)
可以使用 PrepareContext
创建预处理语句
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
ExecContext
、QueryContext
和 QueryRowContext
可以用于语句。使用后,应使用 Close
关闭语句。
事务
事务使用 BeginTx
启动
tx, err := db.BeginTx(ctx, nil)
if err != nil {
log.Fatal(err)
}
前面已介绍的 ExecContext
、QueryContext
、QueryRowContext
和 PrepareContext
方法可以在事务中使用。
处理 NULL
如果数据库列可为 null,则应将支持 null 值的类型之一传递给 Scan。
例如,如果 names 表中的 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
中仅实现了 NullByte
、NullBool
、NullFloat64
、NullInt64
、NullInt32
NullInt16
、NullString
和 NullTime
。特定于数据库的 null 类型的实现留给数据库驱动程序。可以通过实现接口 database/sql/driver.Valuer
和 database/sql.Scanner
来创建支持 NULL
的用户类型。
您还可以传递指针类型。由于需要额外的内存分配,因此请注意性能问题。
var name *string
err := db.QueryRowContext(ctx, "SELECT name FROM names WHERE id = $1", id).Scan(&name)
获取表
如果您希望从 SQL 查询中获取结构数组。
func getTable[T any](rows *sql.Rows) (out []T) {
var table []T
for rows.Next() {
var data T
s := reflect.ValueOf(&data).Elem()
numCols := s.NumField()
columns := make([]interface{}, numCols)
for i := 0; i < numCols; i++ {
field := s.Field(i)
columns[i] = field.Addr().Interface()
}
if err := rows.Scan(columns...); err != nil {
fmt.Println("Case Read Error ", err)
}
table = append(table, data)
}
return table
}
确保处理来自数据库的空值。
type User struct {
UUID sql.NullString
Name sql.NullString
}
rows, err := db.Query("SELECT * FROM Users")
cases := getTable[User](rows)
此内容是 Go Wiki 的一部分。