在Go中连接多个数据库的好习惯是什么?

时间:2017-05-02 21:09:03

标签: go google-cloud-datastore

我试图了解以下是好的还是坏的做法。

如果事实证明这是正常的做法,那么我就可以更轻松地在项目中实现多个数据库连接器。

情况:我已经创建了一个API服务器,每次调用API时,这段代码就会运行:

ctx := context.Background()

client, err := datastore.NewClient(ctx, "foobar")
if err != nil {
    log.Fatalf("Failed to create client: %v", err)
}

该服务每秒收到很多请求,我不确定是否应该在启动时或每次调用API时运行newClient()函数。

PS:
如果另一个连接器是MySQL,则会发生同样的情况。每次API获取请求时,都会运行以下代码:

db, err = sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
if err != nil {
    panic(err.Error())    
}

3 个答案:

答案 0 :(得分:2)

我不确定datastore.Client,但是database.DB管理一个连接池,对于并发使用是安全的,每次你想要的时候都不应该真正调用db.Open执行查询。实际上,Open's文档的最后一段清楚地表明了这一点。

  

返回的数据库对于多个goroutine和并发使用是安全的   维护自己的空闲连接池。因此,Open功能   应该只召唤一次。很少需要关闭数据库。

<强>更新

如果您查看datastore文档中Basic Operations部分示例代码中的注释,您会找到推荐用途。

  

创建数据存储客户端。在典型的应用程序中,您会   创建一个可以为每个数据存储重用的客户端   操作

答案 1 :(得分:0)

我没有使用Google数据存储区的任何经验,但我希望它的设计与database/sql包类似。在这种情况下,在每个请求上使用sql.Open并不是很糟糕,因为连接被懒惰地初始化并且它没有验证参数。但重复使用它会好得多,因为它可以安全地同时使用。

  

虽然在完成数据库时Close()数据库是惯用的,但sql.DB对象的设计是长期存在的。不经常打开()和关闭()数据库。而是为您需要访问的每个不同数据存储创建一个sql.DB对象,并保留它直到程序完成访问该数据存储。根据需要传递它,或者以某种方式在全球范围内提供它,但保持打开状态。并且不要从短期函数中打开()和关闭()。相反,将sql.DB作为参数传递给该短期函数。

     

如果不将sql.DB视为长期存在的对象,则可能会遇到诸如重用不良和连接共享,可用网络资源不足或由于大量TCP连接导致的偶发故障等问题保持TIME_WAIT状态。这些问题表明你没有像设计那样使用数据库/ sql。

来自:http://go-database-sql.org/accessing.html

默认情况下,它由连接池支持,没有连接限制。因此,您可能会使用足够的并发goroutine使其饿死(更不用说某些数据库系统具有非常繁重的连接初始化)。但是,您可以非常轻松地限制池大小:http://go-database-sql.org/connection-pool.html

答案 2 :(得分:0)

这是一个基于偏好的答案,但这是为了它的价值。

使用包github.com/mjibson/goon满足您的所有datastore需求。它很好地包含了GetPut之类的调用,并且会为你制定Marshal / Unmarshal structs。它还会自动通过memcache运行任何关键查询,以加快速度。

回到你的实际问题。 goon适合在每次请求时运行这两行中的一行。

g := goon.FromContext(c) // if you have Context
g := goon.NewGoon(req) // if you have http.Request