我粘贴了一个可重复性最低的测试代码。简而言之,当SetMaxOpenConns
设置为10时,程序将在10之后永远挂起。我在很久以前就发现了这个相关的线程,但它似乎得到了解决和测试:https://github.com/golang/go/issues/6593
请注意,通过注释掉SetMaxOpenConns
,代码可以正常运行。
我做错了什么?还是我应该开一期新的?
1 package main
2
3 import (
4 "database/sql"
5 "log"
6 "time"
7 _ "github.com/lib/pq"
8 )
9
10 func main(){
11 // Establish db connection
12 db, err := sql.Open("postgres", "host=0.0.0.0 port=5432 user=postgres password=password dbname=test sslmode=disable")
13 if err != nil {
14 log.Fatal(err)
15 }
16
17 db.SetMaxOpenConns(10) // commenting this line will resolve the problem
18 db.SetMaxIdleConns(10)
19 db.SetConnMaxLifetime(10 * time.Second)
20
21 // Query more than max open; note that hangs forever
22 for i:=0; i<12; i++ {
23 rows, err := Query(db)
24 if err != nil {
25 log.Fatal(err)
26 }
27 log.Println(i)
28 log.Println(rows)
29 }
30 }
31
32 func Query(db *sql.DB) (*sql.Rows, error){
33 stmt, err := db.Prepare("SELECT * FROM test;")
34 if err != nil {
35 log.Fatal(err)
36 }
37
38 defer stmt.Close()
39
40 rows, err := stmt.Query()
41 if err != nil {
42 log.Fatal(err)
43 }
44
45 return rows, nil
46 }
您需要使用rows.Next
完全迭代结果集和/或调用rows.Close()
;根据文件:
Close关闭行,阻止进一步枚举。如果Next被调用并返回false,并且没有其他结果集,那么Rows将自动关闭,只需检查Err的结果即可。Close是幂等的,不影响Err的结果。
类似于:
for i:=0; i<12; i++ {
rows, err := Query(db)
if err != nil {
log.Fatal(err)
}
log.Println(i)
log.Println(rows)
if err = rows.Close(); err != nil {
panic(err)
}
}
要使其有用,您需要遍历行(请参阅文档中的示例(
到数据库的连接将一直使用,直到结果集关闭(此时它将返回到池(。因为您是在循环中执行此操作的,所以最终会得到10个活动结果集,当您再次调用Query()
时,sql
包将等待连接可用(这永远不会发生(。
请注意,因为您的查询没有参数(并且您只使用过一次stmt
(,所以调用Prepare
没有任何好处;下面的比较简单,并且会有相同的结果:
func Query(db *sql.DB) (*sql.Rows, error) {
return db.Query("SELECT * FROM test;")
}