在Go

时间:2017-02-14 09:50:27

标签: go connection mgo

假设,对于每个请求连接到数据库并在请求完成时关闭是不错的做法?

我正在使用mongodbmgo作为数据库。

在我的项目中,我想通过从请求标头中获取数据库名称来连接到某个数据库(当然,这与身份验证机制相结合,例如我的应用程序中的JWT)。流程如下:

  1. 用户身份验证:

    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
    
  2. 一些RESTful操作

    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
    
  3. 所以我的问题是:

    1. 这可行吗? - 我已经阅读了关于连接池并重用它们但我还没有读过很多关于它们的信息
    2. 有没有更好的方法来实现所需的功能?
    3. 如何确保会话仅在请求完成后关闭?
    4. 我之所以需要这样做是因为我们有多个供应商拥有相同的数据库集合,这些集合具有不同的条目,并且对自己的数据库具有受限访问权。

      更新/解决方案 我最后使用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%。

1 个答案:

答案 0 :(得分:0)

假设不是一个好习惯,因为:

  1. 数据库逻辑分散在多个包中。
  2. 很难测试
  3. 你不能申请DI(主要是维护代码很难)
  4. 回答你的问题:

    1. 是可行的但是你不会在其中使用连接池去包(如果你想了解更多关于连接池的话,请查看代码here
    2. 更好的方法是创建一个包含数据库连接的全局变量,并在应用程序停止时关闭(并且不关闭每个请求的连接)
    3. 如何确保会话仅在请求完成时关闭< - 您应该检查数据库查询的答案,然后关闭连接(但我不建议在请求后关闭连接,因为您'我需要再次打开另一个请求并再次关闭等...)