Prepare
プリペアードステートメントを作成して、クエリを効率的に再利用できます。
Exec Statements
結果を返さないクエリ(INSERT、UPDATE、DELETE など)のプリペアードステートメントを作成します。
ctx := context.Background()
db, err := bob.Open("postgres", "...")
if err != nil {
// ...
}
q := psql.Update(...)
stmt, err := bob.Prepare(ctx, db, q)
if err != nil {
// ...
}
defer stmt.Close()
// ステートメントを実行
result, err := stmt.Exec(ctx, args...)
if err != nil {
// ...
}
使用例
// UPDATE ステートメントの準備
updateQuery := psql.Update("users").
Set("name", psql.Arg("")).
Set("updated_at", psql.Arg(time.Time{})).
Where(psql.Quote("id").EQ(psql.Arg(0)))
updateStmt, err := bob.Prepare(ctx, db, updateQuery)
if err != nil {
return err
}
defer updateStmt.Close()
// 複数のユーザーを更新
for _, user := range users {
result, err := updateStmt.Exec(ctx, user.Name, time.Now(), user.ID)
if err != nil {
return err
}
rowsAffected, _ := result.RowsAffected()
fmt.Printf("Updated %d rows for user %d\n", rowsAffected, user.ID)
}
Query Statements
行を返すクエリのプリペアードステートメントを作成します。bob.PrepareQuery()
または bob.PrepareQueryx()
を使用します。
q := psql.Select(...)
stmt, err := bob.PrepareQuery(ctx, db, q, scan.StructMapper[userObj]())
if err != nil {
// ...
}
defer stmt.Close()
// ステートメントを実行
users, err := stmt.All(ctx, args...)
if err != nil {
// ...
}
使用例
type User struct {
ID int `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
}
// SELECT ステートメントの準備
selectQuery := psql.Select("id", "name", "email").
From("users").
Where(psql.Quote("active").EQ(psql.Arg(true))).
Where(psql.Quote("created_at").GTE(psql.Arg(time.Time{}))).
OrderBy(psql.Quote("id").Asc())
selectStmt, err := bob.PrepareQuery(ctx, db, selectQuery, scan.StructMapper[User]())
if err != nil {
return err
}
defer selectStmt.Close()
// 異なる日付でクエリを実行
dates := []time.Time{
time.Now().AddDate(0, -1, 0), // 1ヶ月前
time.Now().AddDate(0, -3, 0), // 3ヶ月前
time.Now().AddDate(0, -6, 0), // 6ヶ月前
}
for _, date := range dates {
users, err := selectStmt.All(ctx, date)
if err != nil {
return err
}
fmt.Printf("Users since %s: %d\n", date.Format("2006-01-02"), len(users))
}
単一結果の取得
// 単一ユーザーを取得するステートメント
getUserQuery := psql.Select("id", "name", "email").
From("users").
Where(psql.Quote("id").EQ(psql.Arg(0)))
getUserStmt, err := bob.PrepareQuery(ctx, db, getUserQuery, scan.StructMapper[User]())
if err != nil {
return err
}
defer getUserStmt.Close()
// 異なるIDでユーザーを取得
userIDs := []int{1, 2, 3, 4, 5}
for _, userID := range userIDs {
user, err := getUserStmt.One(ctx, userID)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
fmt.Printf("User %d not found\n", userID)
continue
}
return err
}
fmt.Printf("User %d: %s\n", user.ID, user.Name)
}
利用可能なメソッド
Exec Statements
Exec(ctx, args...)
- ステートメントを実行
Query Statements
One(ctx, args...)
- 単一の結果を取得All(ctx, args...)
- 全ての結果を取得Cursor(ctx, args...)
- カーソルを取得
注意点
- リソース管理:
defer stmt.Close()
を必ず使用する - パフォーマンス: 同じクエリを複数回実行する場合に最適
- メモリ効率: プリペアードステートメントはメモリに保存される
- データベース接続: 同じデータベース接続で使用する必要がある
プリペアードステートメントは、同じクエリを異なるパラメータで繰り返し実行する場合に、パフォーマンスを大幅に向上させます。