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

34

我在使用go语言的github.com/go-sql-driver/mysql驱动程序。

我打开一个数据库:

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。

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


1
正好遇到这个问题,非常感谢您的提问! - nights
5个回答

42

sql.Open并不会真正连接到你的数据库。

一个sql.DB维护了连接到你的数据库的一个连接池。每次查询数据库时,你的程序将尝试从这个池中获取一个连接或者创建一个新的连接。当你关闭连接时,它们将被放回到池中。

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

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

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

有关更多信息,请参见http://go-database-sql.org/surprises.html


1
我们的生产系统也遇到了同样的问题。后来我们找到了这篇文章并尝试了其中的方法。它奏效了,因为每个连接都占用主内存,导致内存不足。然后我们配置了SQL服务器,并将连接过期时间设置为1秒。感谢你的帮助,@nussjustin,你为我们铺平了道路。 - Harshit Chaurasia

8
sql.Open返回的*DB对象并不对应于一个单独的连接,它更像是数据库的句柄:为您管理连接池。您可以使用`(*DB).SetMaxOpenConns它们的配对函数来控制打开的连接数目。因此,在这里发生的基本情况是,db.Querydb.QueryRow尝试获取自己的连接,而DB句柄不会对同时打开的连接数施加任何限制,所以当它打开超过mysql可以处理的连接时,您的代码就会崩溃。

4

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


3

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

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

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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接