プリペアドステートメント
パラメータ化クエリを実行します
「プリペアドステートメント」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
Prepared Statementとは
prepared statementは、SQLテキストをデータベースへ1回送信して解析・実行計画を作成し、その後、異なるパラメーターで何度も実行します。クエリを繰り返し実行する場合に高速で、インジェクション対策にもなります。
パラメーターのプレースホルダー
ユーザー入力を連結してSQLを組み立ててはいけません。プレースホルダーを使い、ドライバーが値を分けて送信するようにします。PostgreSQLでは$1, $2を、MySQLとSQLiteでは?を使います。
SELECT * FROM users WHERE age > $1 AND city = $2これでインジェクションを防げる理由
パラメーターはSQLテキストとは別に送信されるため、データベースはパラメーターを常にデータとして厳密に扱い、コードとして解釈することはありません。" OR 1=1のような悪意のある値も、実行可能なSQLではなくリテラル文字列になります。
db.Prepare
Prepareは、プールに関連付けられた*sql.Stmtを返します。その後、ステートメントに対して引数を指定してExecまたはQueryを呼び出します。
stmt, err := db.Prepare("INSERT INTO users(name, age) VALUES($1, $2)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()ステートメントを実行する
各プレースホルダーに対応する引数を指定して、stmt.Execを呼び出します。INSERTやUPDATEでは、Execは影響を受けた行数と最後に挿入したIDを持つsql.Resultを返します。
res, err := stmt.Exec("Ada", 36)
if err != nil {
log.Fatal(err)
}
n, _ := res.RowsAffected()
fmt.Println("inserted", n)ループ内で再利用する
再利用によって効果が得られます。1回だけprepareし、ループ内で何度も実行します。データベースは呼び出しごとに解析済みの実行計画を再利用します。
for _, u := range users {
if _, err := stmt.Exec(u.Name, u.Age); err != nil {
log.Fatal(err)
}
}暗黙的なPrepare
db.Queryまたはdb.Execに直接引数を渡しても、プレースホルダーが安全に使われます。ドライバーが内部でPrepareを実行する場合もあります。明示的なPrepareが重要になるのは、主に同じ処理を繰り返し実行する場合です。
実行可能なパラメータバインディングのシミュレーション
実際のプリペアドステートメントにはデータベースが必要です。この実行可能な例では、安全なパラメータバインディングをシミュレートし、値がクエリ文字列と分離されたままになることを示します。
package main
import "fmt"
func execPrepared(query string, args ...interface{}) string {
return fmt.Sprintf("EXEC %q with args %v", query, args)
}
func main() {
q := "INSERT INTO users(name, age) VALUES($1, $2)"
people := [][2]interface{}{{"Ada", 36}, {"Lin", 41}}
for _, p := range people {
fmt.Println(execPrepared(q, p[0], p[1]))
}
}コンテキストのバリエーション
PrepareContext と stmt.ExecContext を使用すると、他の database/sql の処理と同様に、プリペアド呼び出しでもタイムアウトとキャンセルが適用されます。
Stmtは必ずCloseする
*sql.Stmt はデータベース上のリソースを保持します。使い終わったら stmt.Close() を defer してください。ステートメントを解放しないと、サーバー側のプリペアドステートメント数の上限に達する可能性があります。
ステートメントとコネクションプール
*sql.DB 上でプリペアしたステートメントは、プール内の複数のコネクションで利用できます。ライブラリが、実際に使用されるコネクション上でステートメントを再度プリペアします。通常、これは自分で管理する必要はありません。
理解度チェック
プリペアドステートメントに関する知識を確認しましょう。
まとめ
プリペアドステートメントについて学びました。
- Prepareは一度だけ解析し、何度も実行します
- プレースホルダー($1または?)によって値をデータとして扱い、インジェクションを防ぎます
- stmt.Execは影響を受けた行数を返し、stmt.Close()はdeferします
- ループ内で再利用し、期限を扱う場合はContextのバリエーションを使用します
よくある質問
「プリペアドステートメント」レッスンは無料ですか?
はい。「プリペアドステートメント」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「プリペアドステートメント」で何を学びますか?
パラメータ化クエリを実行します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「プリペアドステートメント」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。