PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Pourquoi même utiliser *DB.exec() ou des instructions préparées dans Golang ?

"Pourquoi même utiliser db.Exec()":

Il est vrai que vous pouvez utiliser db.Exec et db.Query indifféremment pour exécuter les mêmes instructions SQL, mais les deux méthodes renvoient des types de résultats différents. Si implémenté par le pilote, le résultat renvoyé par db.Exec peut vous dire combien de lignes ont été affectées par la requête, tandis que db.Query renverra l'objet rows à la place.

Par exemple, disons que vous voulez exécuter un DELETE et vous voulez savoir combien de lignes ont été supprimées par celle-ci. Vous pouvez le faire de la manière appropriée :

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)

ou la manière la plus détaillée et objectivement la plus coûteuse :

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)

Il existe une troisième façon de procéder avec une combinaison de postgres CTE, SELECT COUNT , db.QueryRow et row.Scan mais je ne pense pas qu'un exemple soit nécessaire pour montrer à quel point une approche serait déraisonnable par rapport à db.Exec .

Une autre raison d'utiliser db.Exec sur db.Query c'est quand vous ne vous souciez pas du résultat renvoyé, quand tout ce dont vous avez besoin est d'exécuter la requête et de vérifier s'il y a eu une erreur ou non. Dans ce cas, vous pouvez faire ceci :

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

D'un autre côté, vous ne pouvez pas (vous pouvez mais vous ne devriez pas) faire ceci :

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

En faisant cela, après un court instant, votre programme paniquera avec une erreur qui dit quelque chose comme too many connections open . C'est parce que vous supprimez le db.Rows renvoyé valeur sans faire d'abord l'obligatoire Close appelez-le, et vous vous retrouvez donc avec le nombre de connexions ouvertes qui augmente et finit par atteindre la limite du serveur.

"ou des déclarations préparées en Golang ?" :

Je ne pense pas que le livre que vous citez soit correct. Au moins pour moi, cela ressemble ou non à un db.Query call crée une nouvelle instruction préparée à chaque fois dépend du pilote que vous utilisez.

Voir par exemple ces deux sections de queryDC (une méthode non exportée appelée par db.Query ) :sans instruction préparée et avec instruction préparée.

Que le livre soit correct ou non, un db.Stmt créé par db.Query serait, à moins qu'il n'y ait une mise en cache interne en cours, jeté après la fermeture des Rows renvoyés objet. Si vous appelez plutôt manuellement db.Prepare puis mettre en cache et réutiliser le db.Stmt renvoyé vous pouvez potentiellement améliorer les performances des requêtes qui doivent être exécutées souvent.

Pour comprendre comment une instruction préparée peut être utilisée pour optimiser les performances, vous pouvez consulter la documentation officielle :https://www.postgresql.org/docs/current/static/sql-prepare.html