J'utilise le pilote github.com/go-sql-driver/mysql pour aller.
J'ouvre une base de données:
db, err := sql.Open("mysql", str)
Ensuite, j'ai deux fonctions qui sont appelées 200 fois chacune avec le code mysql suivant:
rows, err := db.Query("select name from beehives")
if err != nil {
panic(err)
}
defer rows.Close()
La deuxième:
err = db.QueryRow("select id, secret, shortname from beehives where shortname = ?", beehive).Scan(&id, &secre
switch {
case err == sql.ErrNoRows:
err = errors.New("Beehive '"+beehive+"' not found.")
case err != nil:
panic("loginBeehive: "+ err.Error())
default:
// ... do the work
Le premier panique.
Comment peut-il y avoir plusieurs connexions lorsque j'ouvre la base de données une seule fois et comment les fermer?
sql.Open n'ouvre pas vraiment une connexion à votre base de données.
Un sql.DB gère un pool de connexions à votre base de données. Chaque fois que vous interrogez votre base de données, votre programme essaiera d'obtenir une connexion à partir de ce pool ou d'en créer une nouvelle dans le cas contraire. Ces connexions sont ensuite remises dans la piscine une fois que vous les avez fermées.
C'est ce que fait rows.Close()
. Votre db.QueryRow("...")
fait la même chose en interne lorsque vous appelez Scan(...)
.
Le problème de base est que vous créez trop de requêtes, dont chacune a besoin d'une connexion, mais vous ne fermez pas vos connexions assez rapidement. De cette façon, votre programme doit créer une nouvelle connexion pour chaque requête.
Vous pouvez limiter le nombre maximum de connexions que votre programme utilise en appelant SetMaxOpenConns sur votre sql.DB.
Voir http://go-database-sql.org/surprises.html pour plus d'informations.
Le *DB
objet que vous récupérez de sql.Open
ne correspond pas à une connexion unique . Il est préférable de le considérer comme un handle pour la base de données: il gère un pool de connexions pour vous.
Vous pouvez contrôler le nombre de connexions ouvertes avec `(* (DB) .SetMaxOpenConns et sa paire pour les connexions inactives.
Donc, fondamentalement, ce qui se passe ici est que db.Query
et db.QueryRow
essaie d'acquérir une connexion pour eux-mêmes et le handle de base de données ne met aucune restriction sur le nombre de connexions simultanées, donc votre code panique lorsqu'il s'ouvre plus que ce que mysql peut gérer.
Essayez de faire des instructions préparées db.Prepare(query string) (*Stmt, error)
et que stmt.Query
ou stmt.Exec
et que stmt.Close
pour réutiliser les connexions.