我尝试使用Go将一行数据插入到Postgres表中,用于从rabbitmq接收的每个新消息,使用单个连接到DB,该数据库在下面的代码的init函数中打开。 / p>
代码只打开一个连接,而不是只打开一个连接,而是打开497并最大化,导致行插入停止......
我尝试使用这些问题opening and closing DB connection in Go app和open database connection inside a function中的信息,它们说我应该打开一个连接并使用全局db来允许main函数将sql语句传递给在初始化功能。
我以为我已经这样做了,但是为每个新行打开了一个新连接,所以一旦达到postgres连接限制,代码就会停止工作......
我是Go的新手并且编程经验有限,过去两天我一直在努力理解/解决这个问题,而且我真的可以帮助理解我在哪里出错...
var db *sql.DB
func init() {
var err error
db, err = sql.Open ( "postgres", "postgres://postgres:postgres@SERVER/PORT/DB")
if err != nil {
log.Fatal("Invalid DB config:", err)
}
if err = db.Ping(); err != nil {
log.Fatal("DB unreachable:", err)
}
}
func main() {
// RABBITMQ CONNECTION CODE IS HERE
// EACH MESSAGE RECEIVED IS SPLIT TO LEGEND, STATUS, TIMESTAMP VARIABLES
// VARIABLES ARE PASSED TO sqlSatement
sqlStatement := `
INSERT INTO heartbeat ("Legend", "Status", "TimeStamp")
VALUES ($1, $2, $3)
`
// sqlStatement IS THEN PASSED TO db.QueryRow
db.QueryRow(sqlStatement, Legend, Status, TimeStamp)
}
}()
<-forever
}
完整代码如下所示:
package main
import (
"database/sql"
"log"
_ "github.com/lib/pq"
"github.com/streadway/amqp"
"strings"
)
var db *sql.DB
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func init() {
var err error
db, err = sql.Open ( "postgres", "postgres://postgres:postgres@192.168.1.69:5432/test?sslmode=disable")
if err != nil {
log.Fatal("Invalid DB config:", err)
}
if err = db.Ping(); err != nil {
log.Fatal("DB unreachable:", err)
}
}
func main() {
conn, err := amqp.Dial("amqp://Admin:Admin@192.168.1.69:50003/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
q, err := ch.QueueDeclare(
"HEARTBEAT", // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
false, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() {
for d := range msgs {
myString := string(d.Body[:])
result := strings.Split(myString, ",")
Legend := result[0]
Status := result[1]
TimeStamp := result[2]
sqlStatement := `
INSERT INTO heartbeat ("Legend", "Status", "TimeStamp")
VALUES ($1, $2, $3)
`
//
db.QueryRow(sqlStatement, Legend, Status, TimeStamp)
}
}()
<-forever
}
答案 0 :(得分:11)
首先,*sql.DB
不是连接而是连接池,它将打开尽可能多的连接以及postgres服务器允许的连接数。它只在池中没有空闲的连接准备好使用时才打开新连接。
所以问题是DB打开的连接没有被释放,为什么?因为您使用QueryRow
而未在返回的Scan
值上调用*Row
。
引擎盖*Row
拥有一个*Rows
实例,该实例可以访问自己的连接,并且在调用Scan
时会自动释放该连接。如果未调用Scan
,则不会释放连接,导致DB
池在下次调用QueryRow
时打开新连接。因此,由于您没有释放任何连接,DB
会一直打开新的连接,直到它达到postgres设置指定的限制,然后下一次调用QueryRow
挂起,因为它等待连接变为空闲。
因此,如果您不关心输出,则需要使用Exec
,或者需要在返回的Scan
上调用*Row
。