"Waarom zelfs db.Exec() gebruiken":
Het is waar dat u db.Exec
. kunt gebruiken en db.Query
uitwisselbaar om dezelfde sql-instructies uit te voeren, maar de twee methoden retourneren verschillende soorten resultaten. Indien geïmplementeerd door het stuurprogramma, wordt het resultaat geretourneerd door db.Exec
kan u vertellen hoeveel rijen werden beïnvloed door de zoekopdracht, terwijl db.Query
zal in plaats daarvan het rij-object retourneren.
Laten we bijvoorbeeld zeggen dat u een DELETE
. wilt uitvoeren statement en u wilt weten hoeveel rijen er door zijn verwijderd. Je kunt het op de juiste manier doen:
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)
of de meer uitgebreide en objectief duurdere manier:
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)
Er is een derde manier om dit te doen met een combinatie van postgres CTE's, SELECT COUNT
, db.QueryRow
en row.Scan
maar ik denk niet dat een voorbeeld nodig is om te laten zien hoe onredelijk een benadering zou zijn in vergelijking met db.Exec
.
Nog een reden om db.Exec
te gebruiken via db.Query
is wanneer u niet om het geretourneerde resultaat geeft, terwijl u alleen de query hoeft uit te voeren en te controleren of er een fout is opgetreden of niet. In zo'n geval kunt u dit doen:
if _, err := db.Exec(`<my_sql_query>`); err != nil {
panic(err)
}
Aan de andere kant kun je dit niet (je kunt wel, maar je moet het niet doen):
if _, err := db.Query(`<my_sql_query>`); err != nil {
panic(err)
}
Als je dit doet, zal je programma na korte tijd in paniek raken met een fout die iets zegt dat lijkt op too many connections open
. Dit komt omdat u de geretourneerde db.Rows
. weggooit waarde zonder eerst de verplichte Close
. te maken als je het aanroept, krijg je uiteindelijk het aantal open verbindingen dat omhoog gaat en uiteindelijk de limiet van de server bereikt.
"of verklaringen opgesteld in het Golang?":
Ik denk niet dat het boek dat u aanhaalt correct is. Voor mij lijkt het er tenminste op of een db.Query
aanroep maakt elke keer een nieuw voorbereid statement, afhankelijk van het stuurprogramma dat u gebruikt.
Zie bijvoorbeeld deze twee secties van queryDC
(een niet-geëxporteerde methode aangeroepen door db.Query
):zonder voorbereide verklaring en met voorbereide verklaring.
Ongeacht of het boek correct is of niet een db.Stmt
gemaakt door db.Query
zou worden, tenzij er interne caching aan de gang is, weggegooid nadat u de geretourneerde Rows
hebt gesloten voorwerp. Als u in plaats daarvan handmatig db.Prepare
. aanroept en vervolgens cache en hergebruik de geretourneerde db.Stmt
u kunt mogelijk de prestaties verbeteren van de query's die vaak moeten worden uitgevoerd.
Om te begrijpen hoe een opgestelde verklaring kan worden gebruikt om de prestaties te optimaliseren, kunt u de officiële documentatie bekijken:https://www.postgresql.org/docs/current/static/sql-prepare.html