webentwicklung-frage-antwort-db.com.de

Warum überhaupt * DB.exec () oder vorbereitete Anweisungen in Golang verwenden?

Ich benutze Golang mit Postgresql.

Es steht hier , dass wir für Operationen, die keine Zeilen zurückgeben (Einfügen, Löschen, Aktualisieren), exec() verwenden sollten

Wenn ein Funktionsname "Abfrage" enthält, stellt er eine Frage an die Datenbank und gibt eine Reihe von Zeilen zurück, auch wenn diese leer sind. Anweisungen, die keine Zeilen zurückgeben, sollten keine Abfragefunktionen verwenden. Sie sollten Exec () verwenden.

Dann heißt es hier :

Go erstellt für Sie vorbereitete Statements unter dem Deckmantel. Eine einfache db.Query (sql, param1, param2) bereitet beispielsweise die SQL vor, führt sie dann mit den Parametern aus und schließt schließlich die Anweisung.

Wenn query() unter dem Deckmantel vorbereitete Anweisungen verwendet , warum sollte ich mich überhaupt mit vorbereiteten Anweisungen befassen?

8
CommonSenseCode

"Warum überhaupt db.Exec () verwenden?":

Es ist wahr, dass Sie db.Exec Und db.Query Austauschbar verwenden können, um die gleichen SQL-Anweisungen auszuführen. Die beiden Methoden geben jedoch unterschiedliche Ergebnistypen zurück. Wenn vom Treiber implementiert, können Sie anhand des von db.Exec Zurückgegebenen Ergebnisses feststellen, wie viele Zeilen von der Abfrage betroffen waren, während db.Query Stattdessen das Zeilenobjekt zurückgibt.

Angenommen, Sie möchten eine DELETE -Anweisung ausführen und wissen, wie viele Zeilen von ihr gelöscht wurden. Sie können es entweder auf die richtige Weise tun:

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)

oder die ausführlichere und objektiv kostspieligere Art:

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)

Es gibt eine dritte Möglichkeit, dies mit einer Kombination von CTEs für Postgres, SELECT COUNT, db.QueryRow Und row.Scan, Aber ich glaube nicht, dass ein Beispiel notwendig ist, um zu zeigen, wie unvernünftig ein CTE ist Ansatz, der im Vergleich zu db.Exec wäre.

Ein weiterer Grund für die Verwendung von db.Exec Anstelle von db.Query Besteht darin, dass Sie sich nicht um das zurückgegebene Ergebnis kümmern und lediglich die Abfrage ausführen und prüfen müssen, ob ein Fehler aufgetreten ist oder nicht. In einem solchen Fall können Sie dies tun:

if _, err := db.Exec(`<my_sql_query>`); err != nil {
    panic(err)
}

Auf der anderen Seite können Sie dies nicht tun (Sie können, aber Sie sollten es nicht tun):

if _, err := db.Query(`<my_sql_query>`); err != nil {
    panic(err)
}

Wenn Sie dies tun, wird Ihr Programm nach kurzer Zeit mit einem Fehler in Panik geraten, der etwas Ähnliches wie too many connections open Sagt. Dies liegt daran, dass Sie den zurückgegebenen db.Rows - Wert verwerfen, ohne zuvor den obligatorischen Close -Aufruf auszuführen, sodass die Anzahl der offenen Verbindungen steigt und schließlich das Serverlimit erreicht .


"oder vorbereitete Aussagen in Golang?":

Ich denke nicht, dass das Buch, das Sie zitiert haben, richtig ist. Zumindest sieht es für mich so aus, als ob ein db.Query - Aufruf jedes Mal eine neue vorbereitete Anweisung erzeugt, abhängig von dem von Ihnen verwendeten Treiber.

Siehe zum Beispiel diese beiden Abschnitte von queryDC (eine nicht exportierte Methode, die von db.Query Aufgerufen wird): ohne vorbereitete Anweisung und mit vorbereiteter Anweisung .

Unabhängig davon, ob das Buch korrekt ist oder nicht, wird ein db.Stmt - Objekt, das von db.Query Erstellt wurde, nach dem Schließen des zurückgegebenen Rows -Objekts verworfen, sofern kein internes Caching stattfindet . Wenn Sie stattdessen manuell db.Prepare Aufrufen und dann den zurückgegebenen db.Stmt Zwischenspeichern und wiederverwenden, können Sie möglicherweise die Leistung der Abfragen verbessern, die häufig ausgeführt werden müssen.

Um zu verstehen, wie eine vorbereitete Anweisung zur Optimierung der Leistung verwendet werden kann, lesen Sie die offizielle Dokumentation: https://www.postgresql.org/docs/current/static/sql-prepare.html

19
mkopriva