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」を使用するものと使用しないものがあります。
こちらをご覧ください: //github.com/VividCortex/go-database-sql-tutorial
.Queryを使用せず、.Execを使用します。
同時データベースアクセスが多すぎます。 この場合、database / sqlパッケージが将来のバージョンでブロッキングメカニズムを提供するまで、同時接続の数を手動で制限する必要があります。 しかし、多くの場合、キャッシュ/非同期更新がより良い代替手段になります。
おそらく、プログラムがデータベース接続をリークしているだけです。 これは、 db.Query
によって返されたrows
閉じないか、トランザクションを終了するのを忘れた場合に発生します(
私の一般的なアドバイスは使用することです
Scan
何も期待しない場合)、 db.Exec
。 接続は実行後すぐに解放されます。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)
}
}
おかげで、私はそれを手に入れました。
最も参考になるコメント
オプション1:同時実行性が高すぎる
同時データベースアクセスが多すぎます。 この場合、database / sqlパッケージが将来のバージョンでブロッキングメカニズムを提供するまで、同時接続の数を手動で制限する必要があります。 しかし、多くの場合、キャッシュ/非同期更新がより良い代替手段になります。
オプション2:接続のリーク
おそらく、プログラムがデータベース接続をリークしているだけです。 これは、
db.Query
によって返されたrows
閉じないか、トランザクションを終了するのを忘れた場合に発生します(私の一般的なアドバイスは使用することです
Scan
何も期待しない場合)、db.Exec
。 接続は実行後すぐに解放されます。db.QueryRow
。 連鎖構文を使用する場合、db.Query
。 返されたすべての行を読み取る(rows.Next
ループする)か、rows.Close
呼び出すことによって、接続を「解放」することが非常に重要です。 確かに、rows.Close
呼び出しを延期することは良い考えです。 エラーケースなどを忘れないでください。