如何通过打开/关闭数据库用例(上下文管理)避免代码重复?

刚开始使用 Go,我想知道以下情况:

我有一个非常简单的代码库,我只想打开/关闭数据库连接并执行一个简单的查询。我可以按如下方式执行此操作(此处仅显示重要部分):

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func (db *Database) ExecQueryA() {
    dbConn, err := sql.Open("postgres", db.psqlconn)
    if err != nil {
        panic(err)
    }
    defer dbConn.Close()

    _, err = db.Exec(...
    if err != nil {
        panic(err)
    }
}

上面的想法很好,但是如果我想再写 x 个这样的函数,我不想重复这部分:

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func (db *Database) ExecQueryA() {
    dbConn, err := sql.Open("postgres", db.psqlconn)
    if err != nil {
        panic(err)
    }
    defer dbConn.Close()

    _, err = db.Exec(...
    if err != nil {
        panic(err)
    }
}

在每个函数的开头(即我想避免代码重复)。在python中,我会为此编写一个上下文管理器,即我会使用一个with ..语句来为我打开和关闭数据库连接。使用 Go 时,在此用例中避免代码重复的最佳方法是什么?

回答

正如 Brits 在对您的问题的评论中指出的那样,*sql.DB不需要每次打算使用它时都打开和关闭它。相反*sql.DBOpen在您的应用程序启动时, ed的单个共享实例是一种常见且推荐的做法。

... Open 函数应该只调用一次。很少需要关闭数据库。

请注意,这*sql.DB不是一个连接,而是一个管理多个连接的池,在必要时(和可能)打开尽可能多的连接,在必要时保持空闲连接,在不必要时释放它们,等等。最重要的是,它是安全的供并发使用

DB 是表示零个或多个底层连接池的数据库句柄。多个 goroutine 并发使用是安全的。


要回答您的实际问题,减少获取和释放资源重复的一种模式是将函数文字传递给包装函数:

func (db *Database) run(f func(c *sql.DB)) {
    c, err := sql.Open("postgres", db.psqlconn)
    if err != nil {
        panic(err)
    }
    defer c.Close()
    
    f(c)
}

func (db *Database) ExecQueryA() {
    db.run(func(c *sql.DB) {
        _, err := c.Exec(...
        if err != nil {
            panic(err)
        }
    })
}


以上是如何通过打开/关闭数据库用例(上下文管理)避免代码重复?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>