"Hvorfor overhovedet bruge db.Exec()":
Det er rigtigt, at du kan bruge db.Exec
og db.Query
i flæng for at udføre de samme sql-sætninger, men de to metoder returnerer forskellige typer resultater. Hvis det implementeres af driveren, returneres resultatet fra db.Exec
kan fortælle dig, hvor mange rækker der blev påvirket af forespørgslen, mens db.Query
returnerer rækkeobjektet i stedet.
Lad os f.eks. sige, at du vil udføre en DELETE
sætning, og du vil vide, hvor mange rækker der blev slettet af den. Du kan gøre det på den rigtige måde:
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)
eller den mere omfattende og objektivt dyrere måde:
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)
Der er en tredje måde du kan gøre dette på med en kombination af postgres CTE'er, SELECT COUNT
, db.QueryRow
og row.Scan
men jeg tror ikke, at et eksempel er nødvendigt for at vise, hvor urimelig en tilgang det ville være sammenlignet med db.Exec
.
Endnu en grund til at bruge db.Exec
over db.Query
er, når du er ligeglad med det returnerede resultat, hvor alt du behøver er at udføre forespørgslen og kontrollere, om der var en fejl eller ej. I et sådant tilfælde kan du gøre dette:
if _, err := db.Exec(`<my_sql_query>`); err != nil {
panic(err)
}
På den anden side kan du ikke (du kan, men du bør ikke) gøre dette:
if _, err := db.Query(`<my_sql_query>`); err != nil {
panic(err)
}
Hvis du gør dette, vil dit program efter et kort stykke tid gå i panik med en fejl, der siger noget, der ligner too many connections open
. Dette skyldes, at du kasserer de returnerede db.Rows
værdi uden først at gøre den obligatoriske Close
kalde på det, og så ender du med, at antallet af åbne forbindelser stiger og til sidst rammer serverens grænse.
"eller forberedte udsagn i Golang?":
Jeg tror ikke, den bog, du har citeret, er korrekt. I det mindste for mig ser det ud som om det er en db.Query
call opretter en ny forberedt erklæring hver gang afhænger af den driver du bruger.
Se for eksempel disse to sektioner af queryDC
(en ikke-eksporteret metode kaldet af db.Query
):uden udarbejdet erklæring og med udarbejdet erklæring.
Uanset om bogen er korrekt eller ej en db.Stmt
oprettet af db.Query
ville blive smidt væk, medmindre der er intern caching i gang, efter du har lukket de returnerede Rows
objekt. Hvis du i stedet manuelt kalder db.Prepare
og derefter cache og genbrug den returnerede db.Stmt
du kan potentielt forbedre ydeevnen af de forespørgsler, der skal udføres ofte.
For at forstå, hvordan en udarbejdet erklæring kan bruges til at optimere ydeevnen, kan du tage et kig på den officielle dokumentation:https://www.postgresql.org/docs/current/static/sql-prepare.html