私はgithub.com/go-sql-driver/mysqlドライバーを使用しています。
私はデータベースを開きます:
db, err := sql.Open("mysql", str)
次に、次のmysqlコードでそれぞれ200回呼び出される2つの関数があります。
rows, err := db.Query("select name from beehives")
if err != nil {
panic(err)
}
defer rows.Close()
二番目:
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
最初はパニックです。
データベースを1回だけ開いた場合、どのようにして複数の接続が存在する可能性がありますか?
sql.Openは実際にはデータベースへの接続を開きません。
Sql.DBは、データベースへの接続のプールを維持します。データベースをクエリするたびに、プログラムはこのプールから接続を取得するか、そうでない場合は新しい接続を作成しようとします。これらの接続は、いったん閉じるとプールに戻されます。
これはrows.Close()
が行うことです。 db.QueryRow("...")
を呼び出すと、Scan(...)
は内部的に同じことを行います。
基本的な問題は、作成するクエリが多すぎて、それぞれに接続が必要であるにもかかわらず、十分な速さで接続を閉じていないことです。このようにして、プログラムはクエリごとに新しい接続を作成する必要があります。
Sql.DBで SetMaxOpenConns を呼び出すことにより、プログラムが使用する接続の最大数を制限できます。
詳細については、 http://go-database-sql.org/surprises.html を参照してください。
*DB
から取得するオブジェクトsql.Open
はsingle接続に対応していません。これは、データベースのハンドルとして考えるのがよいでしょう。接続プールを管理します。
アイドル状態の接続の場合、 `(* DB).SetMaxOpenConns および そのペア を使用して、開いている接続の数を制御できます。
つまり、基本的にここで発生するのはdb.Query
およびdb.QueryRow
は自分自身の接続を取得しようとし、DBハンドルは同時接続の数に制限を課さないため、mysqlが処理できる以上の数を開くと、コードがパニックになります。
接続を再利用するには、準備されたステートメントをdb.Prepare(query string) (*Stmt, error)
以上stmt.Query
またはstmt.Exec
以上stmt.Close
にしてみてください。