Mysql: あまりにも多くの接続

作成日 2013年07月23日  ·  9コメント  ·  ソース: go-sql-driver/mysql

db.sqlDB.Query()を呼び出すと、「接続が多すぎます」というエラーメッセージが表示されます。 この問題をさらに掘り下げる前に、既知の問題があるかどうか疑問に思います。

考え?

013/07/23 03:05:35 yy.UpdateThingy()db.go:264 [XXXXへのレコードの挿入に失敗しました:エラー1040:接続が多すぎます]

私はgoバージョン1.1.1を使用しています:
goバージョンgo1.1.1linux / 386

私はmysqlドライバーバージョンを使用しています:
v1.0.1

MySqlバージョン:
サーバーバージョン:5.5.22-0ubuntu1(Ubuntu)

これが私のクエリの1つのサンプルです:
行、エラー=
db.sqlDB.Query( "XXXX(yyyy)値(?)に挿入"、
connect.ZZZZ)
if err!= nil {
_ = rows.Close();
結果を返す、エラー
}
_ = rows.Close();

問題が解決することを期待して「rows.Close()」を追加しましたが、サイコロはありません。

参考までに、私のクエリには「rows.Scan」を使用するものと使用しないものがあります。

question working as intended

最も参考になるコメント

オプション1:同時実行性が高すぎる

同時データベースアクセスが多すぎます。 この場合、database / sqlパッケージが将来のバージョンでブロッキングメカニズムを提供するまで、同時接続の数を手動で制限する必要があります。 しかし、多くの場合、キャッシュ/非同期更新がより良い代替手段になります。

オプション2:接続のリーク

おそらく、プログラムがデータベース接続をリークしているだけです。 これは、 db.Queryによって返されたrows閉じないか、トランザクションを終了するのを忘れた場合に発生します

私の一般的なアドバイスは使用することです

  • 行が返されることを期待しない場合(つまり、 Scan何も期待しない場合)、 db.Exec 。 接続は実行後すぐに解放されます。
  • 1行を期待する場合はdb.QueryRow連鎖構文を使用する場合、
  • 複数の行が予想される場合はdb.Query 。 返されたすべての行を読み取る( rows.Nextループする)か、 rows.Close呼び出すことによって、接続を「解放」することが非常に重要です。 確かに、 rows.Close呼び出しを延期することは良い考えです。 エラーケースなどを忘れないでください。

全てのコメント9件

こちらをご覧ください//github.com/VividCortex/go-database-sql-tutorial

.Queryを使用せず、.Execを使用します。

オプション1:同時実行性が高すぎる

同時データベースアクセスが多すぎます。 この場合、database / sqlパッケージが将来のバージョンでブロッキングメカニズムを提供するまで、同時接続の数を手動で制限する必要があります。 しかし、多くの場合、キャッシュ/非同期更新がより良い代替手段になります。

オプション2:接続のリーク

おそらく、プログラムがデータベース接続をリークしているだけです。 これは、 db.Queryによって返されたrows閉じないか、トランザクションを終了するのを忘れた場合に発生します

私の一般的なアドバイスは使用することです

  • 行が返されることを期待しない場合(つまり、 Scan何も期待しない場合)、 db.Exec 。 接続は実行後すぐに解放されます。
  • 1行を期待する場合はdb.QueryRow連鎖構文を使用する場合、
  • 複数の行が予想される場合はdb.Query 。 返されたすべての行を読み取る( rows.Nextループする)か、 rows.Close呼び出すことによって、接続を「解放」することが非常に重要です。 確かに、 rows.Close呼び出しを延期することは良い考えです。 エラーケースなどを忘れないでください。

「db.Query()」を「db.Prepare()およびdb.Exec()」に変更したところ、問題が修正されました。 速くて素晴らしい答えをありがとう。

私もこれを手に入れました。
そして、私は「db.Prepare()とdb.Exec()」を使用します。

var db * sql.DB

func getdb()* sql.DB {
db、err = sql.Open( "mysql"、connArgs)
db.SetMaxIdleConns(100)
データベースを返す
}

func foo(db * sql.DB){
何かをする.....
smint、err:= db.Prepare(....)
smint.Close()を延期する
smint.Exec(....)
}

func main(){
func(){に行く
db = get_db()
db.Close()を延期する
foo(db)
}()
}

1.3に行ってみてください
-----元のメッセージ-----
投稿者:liutaihua [email protected]
受信者:go-sql-driver / mysql [email protected]
件名:Re:[mysql]接続が多すぎます(#111)
日付:2014年7月16日15:43

そして...なぜあなたはメインでゴルーチンを始めるのですか?
コードが実際にこのように見える場合、メインはゴルーチンが実行される前に終了する可能性があり(おそらく終了します)、プログラムは何もしません。
go func(){}()削除するだけです。 あなたは良くなるでしょう。

私の説明で申し訳ありませんが、実際には、コード:

func socke_server(){
にとって {
// receiveとしてaccept_something_from_socket
func(some_receive){
db = get_db()
db.Close()を延期する
foo(db)
}
}
}

func main(){
socke_server()
}

しかし、今はUnixドメインプロトコル( ' user:pwd @ unix (/tmp/mysql.sock)/')を使用しているので、修正されました。

返信ありがとう

あなたもそうすべきではありません-それはうまくいくかもしれませんが、それは遅いです。

受け入れループをメインに配置します。
ゴルーチンをトップレベルの関数に変換します。
get_dbコードをメインの先頭に配置し、db.Closerもそこで(そしてそこだけで)延期します。
このようにデータベースを開閉しないでください。

次のコードを試してください。

func handleConnection(db *sql.DB, args...interface{}) {
    // do someting.....
    // db.Exec("STATEMENT", args...)
}

func main() {
    db, err := sql.Open("mysql", connArgs)
    if err != nil {
        panic(err)
    }
    db.SetMaxIdleConns(100)
    defer db.Close()
    for {
        // accept connections and pass relevant stuff to handleConnection
        go handleConnection(db, nil)
    }
}

おかげで、私はそれを手に入れました。

このページは役に立ちましたか?
0 / 5 - 0 評価