Golang-Postgres ..关闭数据库连接不适用于特定查询

Golang-Postgres ..Closing database connection not working for particular query

我正在使用 golang 访问 postgresql。 这是我的功能

for {
    db, err := database.GetNewConnection(dbname)

    err = db.QueryRow("SELECT COALESCE(COUNT(1),0) FROM table").Scan(&count)

    if count == 0 {

        var insert = "INSERT INTO table(last_update_time,next_update_time,schedule_frequency)" +
            "VALUES(,,)"
        prep_ins, err := db.Prepare(insert)
        if err != nil {
            return
        }
        _, err = prep_ins.Exec(cur_time, 1464718530, 86400)
        if err != nil {
            return
        }
        defer prep_ins.Close()
        defer db.Close()
    } else {
        var sel_str = "SELECT next_update_time FROM table"
        prep_update, err := db.Prepare(sel_str)
        if err != nil {

            return
        }
        _, err = prep_update.Exec()
        if err != nil {
            defer prep_update.Close()
            return
        }
        defer prep_update.Close()
        defer db.Close()
    }
    time.Sleep(10 * 60 * time.Second)
}

每 10 分钟,此函数将 运行 并执行这些语句。它工作正常,但连接将处于空闲状态。我正在使用 pg_stat_activity 检查,状态仅为空闲。每 10 分钟,将创建一个新连接并进入空闲状态 state.so 并继续增加。我不知道为什么会这样。

提前致谢。

for循环是无限循环,永远不会return。这意味着 defer 永远不会被执行,连接也不会被关闭。您需要在循环结束时添加显式 db.Close()

如果您不需要每次执行任务时都需要新的连接,也可以将 db 的初始化移出循环。您可以只创建一个连接并重用它。如果这样做,请将 defer 语句移动到 db 的初始化下方。如果数据库操作 return 出现一些错误,则 defer 将关闭连接。

db, err := database.GetNewConnection(dbname)
if err != nil {
    return fmt.Errorf("Error in creating database connection: %+v", err)
}
defer db.Close()
for {

    // ...

    db.Close()
}

通过这样做,您可以确保在函数 (https://blog.golang.org/defer-panic-and-recover)

的每个 return 路径 put 上关闭连接

如果您仍将 db 初始化留在循环中,请删除 defers,因为它们只会添加到延迟堆栈,而数据库连接将被显式关闭。

正如@abhink 所指出的,由于永久 运行 for 循环,您的 defer 语句未被调用。您使用 for 循环计划执行一段代码的实现不是最佳的。

您应该改用 golang 频道。

package main

import (
    "fmt"
    "time"
)

func main() {
    //You can configure your tick for 10 mnts.
    tick := time.Tick(100 * time.Millisecond)
    //some exit condition
    exit := time.After(1000 * time.Millisecond)
    for {
        select {
        case <-tick:
            poke()
        case <-exit:
            fmt.Println("Exit")
            return
        default:
            fmt.Println("    .")
            time.Sleep(50 * time.Millisecond)
        }
    }
}

func poke() {
    fmt.Println("Opening connection")
    defer fmt.Println("Closing connection")
    fmt.Println("Inserting into Database")
}

您可以更改 pock() 函数以将记录插入数据库。您可以将自动收报机配置为每 10 mnts 自动计时。由于每个 tick 都会触发一个新的函数调用,因此一旦 pock() 函数执行完成,您的 defer 就会被调用。

参考这个 go playground 片段 https://play.golang.org/p/1fQgbmI9LY

defer函数只在函数returns时被调用。在你的循环中,当循环处于活动状态时,defer db.Close() 永远不会执行,因此函数永远不会被调用。

您可以将 for 中的逻辑包装在 闭包 中以实现延迟:

for{
   func(){
       // inner code 
   }()
   time.Sleep(10 * 60 * time.Second)
}