lib / pq postgres驱动程序中的连接泄漏

问题描述 投票:-1回答:1

鉴于db的类型为*sql.DB(使用lib/pq驱动程序,以下代码会导致连接泄漏:

    rows, err := db.Query(
        "select 1 from things where id = $1",
        thing,
    )
    if err != nil {
        return nil, fmt.Errorf("can't select thing (%d): %w", thing, err)
    }

    found := false

    for rows.Next() {
        found = true
        break
    }

反复调用此代码会增加打开的连接数,直到耗尽:

select sum(numbackends) from pg_stat_database;
// 5
// 6
// 7
// ...
// 80

我该如何解决?

sql postgresql go
1个回答
1
投票

您编写的代码有几个问题。您避免连接泄漏的问题的直接答案是关闭rows迭代器as mentioned in the documentation。因此,您使用自己的答案在正确的轨道上,但是您自己的答案缺少一个重要的细节:rows.Close()应该仅被调用一次。循环调用将无效。正常的调用方式是在defer语句中:

    rows, err := db.Query(
        "select 1 from things where id = $1",
        thing,
    )
    if err != nil {
        return nil, fmt.Errorf("can't select thing (%d): %w", thing, err)
    }
    defer rows.Close()

    found := false

    for rows.Next() {
        found = true
        break
    }

最后,由于您所关心的只是一个结果,因此完全没有理由获取多行结果集。这种方法实际上隐式地解决了连接泄漏问题,同时还允许Postgres极大地优化查询:

    row, err := db.QueryRow(
        "select TRUE from things where id = $1 LIMIT 1",
        thing,
    )
    if err != nil {
        return nil, fmt.Errorf("can't select thing (%d): %w", thing, err)
    }
    var found bool
    if err := row.Scan(&found); err != nil {
        return nil, fmt.Errorf("Failed to scan result: %w", err)
    }
© www.soinside.com 2019 - 2024. All rights reserved.