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

ExecContextQueryContextQueryRowContext 可以用于语句。使用后,应使用 Close 关闭语句。

事务

事务使用 BeginTx 启动

tx, err := db.BeginTx(ctx, nil)
if err != nil {
    log.Fatal(err)
}

前面已介绍的 ExecContextQueryContextQueryRowContextPrepareContext 方法可以在事务中使用。

事务必须以调用 CommitRollback 结束。

处理 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 中仅实现了 NullByteNullBoolNullFloat64NullInt64NullInt32 NullInt16NullStringNullTime。特定于数据库的 null 类型的实现留给数据库驱动程序。可以通过实现接口 database/sql/driver.Valuerdatabase/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 的一部分。