Go Wiki:SQLInterface

簡介

database/sql 套件提供一個通用介面,用於 SQL(或類似 SQL)資料庫。有關詳細資訊,請參閱 官方文件

此頁面提供範例使用模式。

資料庫驅動程式

database/sql 套件必須與資料庫驅動程式搭配使用。請參閱 https://go.dev.org.tw/s/sqldrivers 以取得驅動程式清單。

以下文件假設已匯入驅動程式。

連線到資料庫

Open 用於建立資料庫控制代碼

db, err := sql.Open(driver, dataSourceName)

其中驅動程式指定資料庫驅動程式,而 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,
)

其中 result 包含最後的插入 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

如果資料庫欄位為可為空值,則應將支援空值的其中一種類型傳遞至 Scan。

例如,如果 names 表格中的 name 欄位為可為空值

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
}

NullByteNullBoolNullFloat64NullInt64NullInt32 NullInt16NullStringNullTimedatabase/sql 中實作。特定於資料庫的可為空值類型的實作留給資料庫驅動程式。可支援 NULL 的使用者類型可透過實作介面 database/sql/driver.Valuerdatabase/sql.Scanner 來建立。

您也可以傳遞指標類型。小心效能問題,因為它需要額外的記憶體配置。

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 的一部分。