管理Go中每个请求的连接
假设地说,为每个请求连接到数据库并在请求完成时关闭是一种良好的做法吗 我正在对数据库使用管理Go中每个请求的连接,go,connection,mgo,Go,Connection,Mgo,假设地说,为每个请求连接到数据库并在请求完成时关闭是一种良好的做法吗 我正在对数据库使用mongodb和mgo 在我的项目中,我希望通过从请求头获取数据库名称来连接到某个数据库(当然,这与身份验证机制相结合,例如我的应用程序中的JWT)。流程如下所示: func main() { ... // Configure connection and set in global var model.DBSession, err = mgo.DialWithInfo(mongoDB
mongodb
和mgo
在我的项目中,我希望通过从请求头获取数据库名称来连接到某个数据库(当然,这与身份验证机制相结合,例如我的应用程序中的JWT)。流程如下所示:
func main() {
...
// Configure connection and set in global var
model.DBSession, err = mgo.DialWithInfo(mongoDBDialInfo)
defer model.DBSession.Close()
...
n := negroni.Classic()
n.Use(negroni.HandlerFunc(Middleware))
...
}
func Middleware(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
...
db := NewDataStore(clientDomain)
// db.Close() is an alias for ds.session.Close(), code for this function is not included in this post
// Im still experimenting with this, I need to make sure the session is only closed after a request has completed, currently it does not always do so
defer db.Close()
ctx := req.Context()
ctx = context.WithValue(ctx, auth.DataStore, db)
req = req.WithContext(ctx)
...
}
func NewDataStore(db string) *DataStore {
store := &DataStore{
db: DBSession.Copy().DB(db),
session: DBSession.Copy(),
}
return store
}
POST to http://api.app.com/authenticate
// which checks the user in a "global" database,
// authenticates them and returns a signed JWT token
// The token is stored in bolt.db for the authentication mechanism
POST to http://api.app.com/v1/blog/posts
// JWT middleware for each request to /v1* is set up
// `Client-Domain` in header is set to a database's name, e.g 'app-com'
// so we open a connection to that database and close when
// request finishes
Go
内置的Context
,复制了一个会话,并在任何需要执行CRUD操作的地方使用它
比如:
func main() {
...
// Configure connection and set in global var
model.DBSession, err = mgo.DialWithInfo(mongoDBDialInfo)
defer model.DBSession.Close()
...
n := negroni.Classic()
n.Use(negroni.HandlerFunc(Middleware))
...
}
func Middleware(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
...
db := NewDataStore(clientDomain)
// db.Close() is an alias for ds.session.Close(), code for this function is not included in this post
// Im still experimenting with this, I need to make sure the session is only closed after a request has completed, currently it does not always do so
defer db.Close()
ctx := req.Context()
ctx = context.WithValue(ctx, auth.DataStore, db)
req = req.WithContext(ctx)
...
}
func NewDataStore(db string) *DataStore {
store := &DataStore{
db: DBSession.Copy().DB(db),
session: DBSession.Copy(),
}
return store
}
然后在HandlerFunc中使用它,例如/v1/system/users
:
func getUsers(res http.ResponseWriter, req *http.Request) {
db := req.Context().Value(auth.DataStore).(*model.DataStore)
users := make([]SystemUser{}, 0)
// db.C() is an alias for ds.db.C(), code for this function is not included in this post
db.C("system_users").Find(nil).All(&users)
}
与我试验的原始方法相比,响应时间减少了40%。假设这不是一个好的做法,因为:
docker
容器,该网站拥有自己的mongodb
服务器。我们跟踪每个docker
容器的所有者以及如何从“main”Go
服务器访问它们。因此,区别实际上只是谁可以从main
Go
服务器中访问哪个数据库。并非所有情况下,相同的集合都意味着相同的逻辑(可能查询应该不同)。无论如何,对于这种情况,您可以尝试创建一个连接到更多主机的全局变量,请看一看,这已经解释得很清楚了。然后,如果您发现查询速度很慢,您可以随时添加连接,谢谢您的帮助。我将对此进行一些研究,并尝试为我的应用程序提出最佳解决方案。在您的第二个回答中,您说“创建包含数据库连接的全局变量”,但这将限制我一次只能连接一个数据库,对吗?我可以创建一个包含多个连接的全局slice变量并在应用程序死机时关闭所有连接吗?这取决于:主要是因为通过拨号,您可以一次连接到多个主机,然后您可以使用更改数据库的命令来更改Mongo数据库。这取决于你。但是,imho,每个db单独连接更干净。通过这样做,您还可以拆分每个db逻辑。您所说的db逻辑是什么意思?每个数据库都有相同的集合。假设您正在为SaaS网站托管/编辑复制shopify或类似服务,每当新用户注册并创建网站时,我们都会为他们的“专用”网站启动一个新的docker
容器,该网站拥有自己的mongodb
服务器。我们跟踪每个docker
容器的所有者以及如何从“main”Go
服务器访问它们。因此,区别实际上只是谁可以从main
Go
服务器中访问哪个数据库。并非所有情况下,相同的集合都意味着相同的逻辑(可能查询应该不同)。无论如何,对于这种情况,您可以尝试创建一个连接到更多主机的全局变量,请看一看,这已经解释得很清楚了。然后,如果您发现查询速度很慢,您可以随时添加连接,谢谢您的帮助。我将对此进行一些研究,并尝试为我的应用程序提出最佳解决方案