"Mengapa bahkan menggunakan db.Exec()":
Memang benar bahwa Anda dapat menggunakan db.Exec
dan db.Query
secara bergantian untuk mengeksekusi pernyataan sql yang sama namun kedua metode mengembalikan jenis hasil yang berbeda. Jika diimplementasikan oleh driver, hasilnya dikembalikan dari db.Exec
dapat memberi tahu Anda berapa banyak baris yang terpengaruh oleh kueri, sementara db.Query
akan mengembalikan objek baris sebagai gantinya.
Misalnya katakanlah Anda ingin menjalankan DELETE
pernyataan dan Anda ingin tahu berapa banyak baris yang dihapus olehnya. Anda dapat melakukannya dengan cara yang benar:
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)
atau cara yang lebih bertele-tele dan secara objektif lebih mahal:
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)
Ada cara ketiga Anda dapat melakukan ini dengan kombinasi CTE postgres, SELECT COUNT
, db.QueryRow
dan row.Scan
tapi saya rasa contoh tidak diperlukan untuk menunjukkan betapa tidak masuk akalnya suatu pendekatan jika dibandingkan dengan db.Exec
.
Alasan lain untuk menggunakan db.Exec
melalui db.Query
adalah ketika Anda tidak peduli dengan hasil yang dikembalikan, ketika yang Anda butuhkan hanyalah menjalankan kueri dan memeriksa apakah ada kesalahan atau tidak. Dalam kasus seperti ini, Anda dapat melakukan ini:
if _, err := db.Exec(`<my_sql_query>`); err != nil {
panic(err)
}
Di sisi lain, Anda tidak bisa (Anda bisa tetapi tidak boleh) melakukan ini:
if _, err := db.Query(`<my_sql_query>`); err != nil {
panic(err)
}
Melakukan ini, setelah beberapa saat, program Anda akan panik dengan kesalahan yang mengatakan sesuatu yang mirip dengan too many connections open
. Ini karena Anda membuang db.Rows
. yang dikembalikan nilai tanpa terlebih dahulu membuat wajib Close
panggil saja, dan Anda akan berakhir dengan jumlah koneksi terbuka yang meningkat dan akhirnya mencapai batas server.
"atau menyiapkan pernyataan dalam bahasa Golang?":
Saya rasa buku yang Anda kutip itu tidak benar. Setidaknya bagi saya itu terlihat seperti apakah db.Query
. atau tidak panggilan membuat pernyataan baru yang disiapkan setiap kali tergantung pada driver yang Anda gunakan.
Lihat misalnya dua bagian queryDC
ini (metode yang tidak diekspor disebut oleh db.Query
):tanpa pernyataan siap dan dengan pernyataan siap.
Terlepas dari apakah buku itu benar atau tidak sebuah db.Stmt
dibuat oleh db.Query
akan, kecuali ada beberapa caching internal yang terjadi, dibuang setelah Anda menutup Rows
yang dikembalikan obyek. Jika Anda secara manual memanggil db.Prepare
lalu tembolok dan gunakan kembali db.Stmt
yang dikembalikan Anda berpotensi dapat meningkatkan kinerja kueri yang perlu sering dijalankan.
Untuk memahami bagaimana pernyataan yang disiapkan dapat digunakan untuk mengoptimalkan kinerja, Anda dapat melihat dokumentasi resmi:https://www.postgresql.org/docs/current/static/sql-prepare.html