Go Wiki: SQLInterface
引言
database/sql 包提供了圍繞 SQL(或類 SQL)資料庫的通用介面。有關詳細資訊,請參閱官方文件。
本頁提供使用模式示例。
資料庫驅動程式
database/sql 包必須與資料庫驅動程式一起使用。請參閱https://golang.com.tw/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,
)
其中 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
可以在語句上呼叫 ExecContext、QueryContext 和 QueryRowContext。使用完畢後,應使用 Close 關閉語句。
事務
事務使用 BeginTx 啟動。
tx, err := db.BeginTx(ctx, nil)
if err != nil {
log.Fatal(err)
}
前面介紹的 ExecContext、QueryContext、QueryRowContext 和 PrepareContext 方法可以在事務中使用。
處理 NULL
如果資料庫列允許為空,則應將支援 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
}
在 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
}
請確保處理來自資料庫的 NULL 值。
type User struct {
UUID sql.NullString
Name sql.NullString
}
rows, err := db.Query("SELECT * FROM Users")
cases := getTable[User](rows)
此內容是 Go Wiki 的一部分。