PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

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

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

Es stimmt, dass Sie db.Exec verwenden können und db.Query austauschbar, um dieselben SQL-Anweisungen auszuführen, die beiden Methoden geben jedoch unterschiedliche Arten von Ergebnissen zurück. Falls vom Treiber implementiert, das von db.Exec zurückgegebene Ergebnis kann Ihnen sagen, wie viele Zeilen von der Abfrage betroffen waren, während db.Query gibt stattdessen das rows-Objekt zurück.

Nehmen wir zum Beispiel an, Sie möchten ein DELETE ausführen -Anweisung und Sie möchten wissen, wie viele Zeilen dadurch gelöscht wurden. Sie können es 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 teurere 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 aus Postgres-CTEs zu tun, SELECT COUNT , db.QueryRow und row.Scan aber ich denke nicht, dass ein Beispiel notwendig ist, um zu zeigen, wie unvernünftig ein Ansatz wäre, wenn man ihn mit db.Exec vergleicht .

Ein weiterer Grund, db.Exec zu verwenden über db.Query ist, wenn Sie sich nicht um das zurückgegebene Ergebnis kümmern, wenn Sie nur die Abfrage ausführen und prüfen müssen, ob ein Fehler aufgetreten ist oder nicht. In einem solchen Fall können Sie Folgendes tun:

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

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

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

Wenn Sie dies tun, gerät Ihr Programm nach kurzer Zeit mit einem Fehler in Panik, der so etwas wie too many connections open besagt . Dies liegt daran, dass Sie die zurückgegebenen db.Rows verwerfen Wert, ohne vorher das obligatorische Close auszuführen Rufen Sie ihn an, und Sie enden damit, dass die Anzahl der offenen Verbindungen steigt und schließlich das Limit des Servers erreicht.

"oder vorbereitete Aussagen in Golang?":

Ich glaube nicht, dass das Buch, das Sie zitiert haben, richtig ist. Zumindest sieht es für mich danach aus, ob eine db.Query Aufruf erstellt jedes Mal eine neue vorbereitete Anweisung, abhängig vom 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, eine db.Stmt erstellt von db.Query würde verworfen, nachdem Sie die zurückgegebenen Rows geschlossen haben, es sei denn, es findet ein internes Caching statt Objekt. Wenn Sie stattdessen manuell db.Prepare aufrufen und dann die zurückgegebene db.Stmt zwischenspeichern und wiederverwenden Sie können möglicherweise die Leistung der Abfragen verbessern, die häufig ausgeführt werden müssen.

Um zu verstehen, wie eine vorbereitete Anweisung verwendet werden kann, um die Leistung zu optimieren, können Sie einen Blick auf die offizielle Dokumentation werfen:https://www.postgresql.org/docs/current/static/sql-prepare.html