「db.Exec()を使用する理由」:
db.Exec
を使用できるのは事実です およびdb.Query
同じSQLステートメントを実行するために交換可能ですが、2つのメソッドは異なるタイプの結果を返します。ドライバによって実装された場合、結果はdb.Exec
から返されます db.Query
がクエリの影響を受けた行数を知ることができます 代わりにrowsオブジェクトを返します。
たとえば、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)
postgresCTEの組み合わせでこれを行うことができる3番目の方法があります。SELECT COUNT
、db.QueryRow
およびrow.Scan
しかし、db.Exec
と比較した場合のアプローチがいかに不合理であるかを示すために例は必要ないと思います。 。
db.Exec
を使用するもう1つの理由 db.Query
を介して 返される結果を気にしないとき、必要なのはクエリを実行してエラーがあったかどうかを確認することだけのときです。このような場合、これを行うことができます:
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
に似たエラーが表示されます。 。これは、返されたdb.Rows
を破棄しているためです。 最初に必須のClose
を作成せずに値 それを呼び出すと、開いている接続の数が増え、最終的にサーバーの制限に達することになります。
"またはGolangでプリペアドステートメント?":
あなたが引用した本は正しくないと思います。少なくとも私には、db.Query
かどうかのように見えます callは、使用しているドライバーに応じて、毎回新しいプリペアドステートメントを作成します。
たとえば、queryDC
のこれら2つのセクションを参照してください。 (db.Query
によって呼び出されるエクスポートされていないメソッド ):プリペアドステートメントなしおよびプリペアドステートメントあり。
本が正しいかどうかに関係なく、db.Stmt
db.Query
によって作成されました 内部キャッシュが実行されていない限り、返されたRows
を閉じた後に破棄されます。 物体。代わりに手動でdb.Prepare
を呼び出す場合 次に、返されたdb.Stmt
をキャッシュして再利用します 頻繁に実行する必要のあるクエリのパフォーマンスを向上させる可能性があります。
プリペアドステートメントを使用してパフォーマンスを最適化する方法を理解するには、公式ドキュメントを参照してください:https://www.postgresql.org/docs/current/static/sql-prepare.html