在Go语言中使用SQL驱动进行连接池管理

huangapple go评论91阅读模式
英文:

Connection pooling with SQL driver in Go

问题

在Go语言中,存储数据库连接的最佳实践是什么?

在Java中,例如可以使用单例模式或一些IoC容器(如Spring)。在Go语言中,最佳实践是什么?它的生命周期如何管理?如何在应用程序关闭后释放连接?

英文:

What is the best practice for storing a connection to a database in Go language?

In Java for example you can use singletons, some IoC containers like Spring.
What is the best practice in it's lifecycle?
How to release it after application close?

答案1

得分: 13

在这里使用单例模式没有任何问题。

我会这样使用:

var db *sql.DB = nil

func GetDB() (*sql.DB, error) {
    if db == nil {
        conn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=require",
            DB_HOST, DB_USER, DB_PASSWORD, DB_NAME)
        log.Println("Creating a new connection: %v", conn)

        d, err := sql.Open("postgres", conn)
        if err != nil {
            return nil, err
        }
        db = d
    }

    return db, nil
}

通过这个导出的函数,你可以从其他包中获取连接。

根据评论更新答案(感谢所有人的信息)!

返回的 DB 可以被多个 goroutine 并发使用,并且维护自己的空闲连接池。因此,应该只调用一次 Open 函数。很少需要关闭 DB。¹

很少需要关闭 DB,因为 DB 句柄应该是长期存在的,并在许多 goroutine 之间共享。²

我认为没有强制要求在数据库连接上调用 close。我没有找到其他的说法。尽管如此,我会在 main 函数中使用 defer GetDB().Close(),只是为了代码的完整性。

另外,我想指出的是,连接应该通过 db.Ping() 进行验证,否则连接可能建立,但数据库可能不存在。

有了这些新的信息,我不会费心使用互斥锁来确保数据库的建立。我会创建一个新的 DBInit() 函数,并在主包的 init() 函数中运行它。

英文:

There is nothing wrong about using a Singleton pattern here too.

I would use something like this:

var db *sql.DB = nil

func GetDB() (*sql.DB, error) {
	if db == nil {
		conn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=require",
			DB_HOST, DB_USER, DB_PASSWORD, DB_NAME)
		log.Println("Creating a new connection: %v", conn)

		d, err := sql.Open("postgres", conn)
		if err != nil {
			return nil, err
		}
		db = d
	}

	return db, nil
}

With this exported function you can receive a connection from all other packages.

Update of the answer according to the comments (thanks @all for the information)!:

> The returned DB is safe for concurrent use by multiple goroutines and
> maintains its own pool of idle connections. Thus, the Open function
> should be called just once. It is rarely necessary to close a DB.¹

> It is rare to Close a DB, as the DB handle is meant to be long-lived
> and shared between many goroutines.²

I would say that there is no forcing reason to call close on the database connection. I found no other statements. Despite this I would use a defer GetDB().close() in the main function - just for the completeness of the code.

Another thing I would like to note is that the connection should be verified by a db.Ping() otherwise the connection could be established but the database may not exist.

With this new information I wouldn't bother using some mutexes to ensure that the database is established. I would create a new DBInit() and run it inside the init() function of the main package.

huangapple
  • 本文由 发表于 2015年11月30日 17:51:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/33995668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定