Go Wiki: SQLInterface
はじめに
database/sql
パッケージは、SQL(またはSQLライク)データベースに関する汎用インターフェースを提供します。詳細については、公式ドキュメントを参照してください。
このページでは、使用パターンの例を示します。
データベースドライバ
database/sql
パッケージは、データベースドライバと組み合わせて使用する必要があります。ドライバのリストについては、https://go.dokyumento.jp/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
メソッドをトランザクションで使用できます。
トランザクションは、Commit
またはRollback
の呼び出しで終了する必要があります。
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型の実装は、データベースドライバに任されています。NULL
をサポートするユーザ型は、インターフェースdatabase/sql/driver.Valuer
とdatabase/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
}
データベースからのNULLを処理するようにしてください。
type User struct {
UUID sql.NullString
Name sql.NullString
}
rows, err := db.Query("SELECT * FROM Users")
cases := getTable[User](rows)
このコンテンツはGo Wikiの一部です。