Golang,mysql:错误 1040:连接过多

huangapple go评论96阅读模式
英文:

Golang, mysql: Error 1040: Too many connections

问题

我正在使用github.com/go-sql-driver/mysql驱动程序来进行Go语言开发。

我打开了一个数据库:

db, err := sql.Open("mysql", str)

然后我有两个函数,每个函数被调用200次,使用以下的mysql代码:

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

第一个函数出现了panic错误。

当我只打开一次数据库时,为什么会有多个连接,我该如何关闭它们?

英文:

I'm using the github.com/go-sql-driver/mysql driver for go.

I open a database:

db, err := sql.Open("mysql", str)

Then I have two functions that are called 200 times each with following mysql code:

rows, err := db.Query("select name from beehives")
if err != nil {
    panic(err)
}       
defer rows.Close()

The second:

    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

The first one is panicing.

How can there be more than one connection when I open the database only once and how do I close them?

答案1

得分: 42

sql.Open并不真正打开与数据库的连接。

sql.DB维护着一个连接池,用于连接数据库。每次查询数据库时,程序会尝试从连接池中获取一个连接,如果没有可用连接,则会创建一个新的连接。关闭连接后,这些连接会被放回连接池中。

这就是rows.Close()的作用。当你调用Scan(...)时,你的db.QueryRow("...")内部也会执行相同的操作。

基本问题在于你创建了太多的查询,每个查询都需要一个连接,但你没有及时关闭连接。这样,你的程序就必须为每个查询创建一个新的连接。

你可以通过在sql.DB上调用SetMaxOpenConns来限制程序使用的最大连接数。

更多信息请参考http://go-database-sql.org/surprises.html。

英文:

sql.Open doesn't really open a connection to your database.

A sql.DB maintains a pool of connections to your database. Each time you query your database your program will try to get a connection from this pool or create a new one otherwise. These connections are than put back into the pool once you close them.

This is what rows.Close() does.
Your db.QueryRow("...") does the same thing internally when you call Scan(...).

The basic problem is that you're creating too many queries, of which each one needs a connection, but you are not closing your connections fast enough. This way your program has to create a new connection for each query.

You can limit the maximum number of connections your program uses by calling SetMaxOpenConns on your sql.DB.

See http://go-database-sql.org/surprises.html for more information.

答案2

得分: 8

sql.Open返回的*DB对象并不对应于一个单独的连接。它更好地被视为数据库的句柄:它为您管理连接池。

您可以使用(*DB).SetMaxOpenConns和它的配对函数来控制打开的连接数,以及用于空闲连接的函数。

所以基本上在这里发生的是,db.Querydb.QueryRow尝试为自己获取连接,而DB句柄对同时连接的数量没有任何限制,所以当它打开超过mysql可以处理的连接数时,您的代码会发生恐慌。

英文:

The *DB object that you get back from sql.Open doesn't corresponds to a single connection. It is better thought as a handle for the database: it manages a connection pool for you.

You can control the number of open connections with `(*DB).SetMaxOpenConns and its pair for idling connections.

So basically what happens here is that db.Query and db.QueryRow tries to acquire a connection for themselves and the DB handle doesn't put any restrictions on the number of simultaneous connections so your code panics when it opens more than what mysql can handle.

答案3

得分: 4

尝试使用预处理语句db.Prepare(query string) (*Stmt, error),然后使用stmt.Querystmt.Exec,最后使用stmt.Close来重用连接。

英文:

Try to make prepared statements db.Prepare(query string) (*Stmt, error) and than stmt.Query or stmt.Exec and than stmt.Close to reuse connections.

答案4

得分: 3

你好,你可以尝试在使用后关闭连接:

db, err := sql.Open("mysql", str)
defer db.Close() // 在作用域结束后关闭连接

这段代码使用了 sql.Open 函数打开了一个 MySQL 数据库连接,并使用 defer 关键字延迟关闭连接,确保在作用域结束后关闭连接。

英文:

hi can you try close connection after used

db, err := sql.Open("mysql", str)
defer db.Close() // close after end scope

答案5

得分: 1

我的程序始终连接到数据库。(用于实时人脸识别考勤)

因此,打开和关闭数据库连接是没有意义的。

因此,只有在初始化程序时才保持打开数据库连接。

func GetAllFaces() interface{} {
    OpenDatabaseConnection() ...
}

但是稍后访问数据库时,增加了连接数并导致程序崩溃。但是关闭rows对象可以将活动连接数保持在最低水平。(对我来说是1)

func SaveAttendance(faceId int, date time.Time) error {
    sqlQuery := fmt.Sprintf("SELECT ... "))
    
    rows, err := DB.Query(sqlQuery) ...
    err = rows.Close()
    return err
}
英文:

My program is connecting always to database. (Realtime Face Recognition for Attendance)

Therefore opening and closing database connection is worthless.

Therefore it's keep opens the database connection only initializing the program.

func GetAllFaces() interface{} {
	OpenDatabaseConnection() ... 
}

But access database later, increased the no of connection and crashed the program. But closing the rows object kept no of active connection at minimum. (for me 1)

 func SaveAttendance(faceId int, date time.Time) error {
    sqlQuery := fmt.Sprintf("SELECT ... "))
    
    rows, err := DB.Query(sqlQuery) ...
    err = rows.Close()
    return err
}

huangapple
  • 本文由 发表于 2015年1月25日 18:55:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/28135580.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定