なぜGolangで* DB.exec()または準備されたステートメントを使用するのですか?
GolangをPostgresqlで使用しています。
here 行を返さない操作(挿入、削除、更新)にはexec()
を使用する必要がある
関数名にクエリが含まれている場合、データベースに質問するように設計されており、空であっても行のセットを返します。行を返さないステートメントでは、クエリ関数を使用しないでください。 Exec()を使用する必要があります。
次に、 ここ :
Goは、カバーの下で準備されたステートメントを作成します。たとえば、単純なdb.Query(sql、param1、param2)は、sqlを準備し、それをパラメーターで実行し、最後にステートメントを閉じることで機能します。
query()
がカバーされたステートメントの下で使用する場合なぜ準備されたステートメントを使用する必要がありますか?
「db.Exec()を使用する理由」:
db.Exec
とdb.Query
を同じように使用して同じsqlステートメントを実行できるのは事実ですが、2つのメソッドは異なるタイプの結果を返します。ドライバーによって実装される場合、db.Exec
から返された結果は、クエリによって影響を受けた行数を示すことができますが、db.Query
は代わりに行オブジェクトを返します。
たとえば、DELETE
ステートメントを実行し、それによって削除された行数を知りたいとします。適切な方法でそれを行うことができます:
res, err := db.Exec(`DELETE FROM my_table WHERE expires_at = $1`, time.Now())
if err != nil {
panic(err)
}
numDeleted, err := res.RowsAffected()
if err != nil {
panic(err)
}
print(numDeleted)
または、より冗長で客観的にコストの高い方法:
rows, err := db.Query(`DELETE FROM my_table WHERE expires_at = $1 RETURNING *`, time.Now())
if err != nil {
panic(err)
}
defer rows.Close()
var numDelete int
for rows.Next() {
numDeleted += 1
}
if err := rows.Err(); err != nil {
panic(err)
}
print(numDeleted)
Postgres CTE、SELECT COUNT
、db.QueryRow
、およびrow.Scan
の組み合わせでこれを行うことができる3番目の方法がありますが、どのように不合理なアプローチを示すために例が必要であるとは思わないdb.Exec
と比較した場合。
db.Exec
over db.Query
を使用するもう1つの理由は、返された結果を気にせず、必要なのはクエリを実行してエラーの有無を確認することだけである場合です。そのような場合、これを行うことができます:
if _, err := db.Exec(`<my_sql_query>`); err != nil {
panic(err)
}
一方、これはできません(できますが、できません)。
if _, err := db.Query(`<my_sql_query>`); err != nil {
panic(err)
}
これを行うと、しばらくすると、プログラムはtoo many connections open
に類似したエラーを示すパニックに陥ります。これは、最初に必須のClose
呼び出しを行わずに、返されたdb.Rows
値を破棄するため、開いている接続の数が増え、最終的にサーバーの制限に達するためです。
「またはGolangでステートメントを準備しましたか?」:
あなたが引用した本は正しいとは思わない。少なくとも私にとっては、db.Query
呼び出しが使用するドライバーに依存するたびに新しい準備されたステートメントを作成するかどうかのように見えます。
たとえば、queryDC
(db.Query
によって呼び出される非エクスポートメソッド)の次の2つのセクションを参照してください: 準備済みステートメントなし および 準備済みステートメント付き 。
ブックが正しいかどうかに関係なく、db.Stmt
によって作成されたdb.Query
は、内部キャッシュが行われていない限り、返されたRows
オブジェクトを閉じた後に破棄されます。代わりに手動でdb.Prepare
を呼び出してから、返されたdb.Stmt
をキャッシュして再利用すると、頻繁に実行する必要があるクエリのパフォーマンスを潜在的に改善できます。
準備済みステートメントを使用してパフォーマンスを最適化する方法を理解するには、公式ドキュメントをご覧ください: https://www.postgresql.org/docs/current/static/sql-prepare.html