web-dev-qa-db-fra.com

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

J'utilise golang avec Postgresql.

Il est dit ici que pour les opérations qui ne renvoient pas de lignes (insérer, supprimer, mettre à jour), nous devrions utiliser exec()

Si un nom de fonction inclut Query, il est conçu pour poser une question à la base de données et renverra un ensemble de lignes, même s'il est vide. Les instructions qui ne renvoient pas de lignes ne doivent pas utiliser les fonctions de requête; ils devraient utiliser Exec ().

Ensuite, il dit ici :

Go crée des relevés préparés pour vous sous les couvertures. Une simple db.Query (sql, param1, param2), par exemple, fonctionne en préparant le sql, puis en l'exécutant avec les paramètres et enfin en fermant l'instruction.

Si query() utilise sous les couvertures des instructions préparées pourquoi devrais-je même prendre la peine d'utiliser des instructions préparées?

8
CommonSenseCode

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

Il est vrai que vous pouvez utiliser db.Exec Et db.Query De manière interchangeable pour exécuter les mêmes instructions SQL, mais les deux méthodes renvoient des types de résultats différents. S'il est 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 à la place l'objet lignes.

Par exemple, supposons que vous souhaitiez exécuter une instruction DELETE et que vous souhaitiez 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 plus verbeuse et objectivement 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 le faire avec une combinaison de CTE postgres, SELECT COUNT, db.QueryRow Et row.Scan Mais je ne pense pas qu'un exemple soit nécessaire pour montrer à quel point un approche qui serait par rapport à db.Exec.

Une autre raison d'utiliser db.Exec Sur db.Query Est lorsque vous ne vous souciez pas du résultat renvoyé, lorsque 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 un tel cas, vous pouvez le faire:

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 de semblable à too many connections open. Cela est dû au fait que vous supprimez la valeur db.Rows Renvoyée sans effectuer d'abord l'appel Close obligatoire, et vous vous retrouvez donc avec le nombre de connexions ouvertes qui augmentent et finissent par atteindre la limite du serveur .


"ou préparé des déclarations à Golang?":

Je ne pense pas que le livre que vous avez cité soit correct. Au moins pour moi, il semble que si un appel db.Query Crée ou non une nouvelle instruction préparée à chaque fois, cela 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, sauf s'il y a une mise en cache interne, jeté après la fermeture de l'objet Rows retourné . Si vous appelez plutôt db.Prepare Manuellement, puis mettez en cache et réutilisez 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

19
mkopriva