web-dev-qa-db-ja.com

Golang、mysql:エラー1040:接続が多すぎます

私は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回だけ開いた場合、どのようにして複数の接続が存在する可能性がありますか?

22
Michael

sql.Openは実際にはデータベースへの接続を開きません。

Sql.DBは、データベースへの接続のプールを維持します。データベースをクエリするたびに、プログラムはこのプールから接続を取得するか、そうでない場合は新しい接続を作成しようとします。これらの接続は、いったん閉じるとプールに戻されます。

これはrows.Close()が行うことです。 db.QueryRow("...")を呼び出すと、Scan(...)は内部的に同じことを行います。

基本的な問題は、作成するクエリが多すぎて、それぞれに接続が必要であるにもかかわらず、十分な速さで接続を閉じていないことです。このようにして、プログラムはクエリごとに新しい接続を作成する必要があります。

Sql.DBで SetMaxOpenConns を呼び出すことにより、プログラムが使用する接続の最大数を制限できます。

詳細については、 http://go-database-sql.org/surprises.html を参照してください。

26
nussjustin

*DBから取得するオブジェクトsql.Opensingle接続に対応していません。これは、データベースのハンドルとして考えるのがよいでしょう。接続プールを管理します。

アイドル状態の接続の場合、 `(* DB).SetMaxOpenConns および そのペア を使用して、開いている接続の数を制御できます。

つまり、基本的にここで発生するのはdb.Queryおよびdb.QueryRowは自分自身の接続を取得しようとし、DBハンドルは同時接続の数に制限を課さないため、mysqlが処理できる以上の数を開くと、コードがパニックになります。

6
tmichel

接続を再利用するには、準備されたステートメントをdb.Prepare(query string) (*Stmt, error)以上stmt.Queryまたはstmt.Exec以上stmt.Closeにしてみてください。

3
Uvelichitel