doudou20080720 2017-02-14 09:50
浏览 90
已采纳

在Go中按请求管理连接

Hypothetically speaking, is it good practice to connect to a database for each request and close in when the request has completed?

I'm using mongodb with mgo for the database.

In my project, I would like to connect to a certain database by getting the database name from the request header (of course, this is combined with an authentication mechanism, e.g. JWT in my app). The flow goes something like:

  1. User authentication:

    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. Some RESTful operations

    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
    

So my questions are:

  1. Is this feasible? - I've read about connection pools and reusing them but I haven't read much about them yet
  2. Is there a better way of achieving the desired functionality?
  3. How do I ensure the session is only closed when the request has completed?

The reason why I need to do this is because we have multiple vendors that have the same database collections with different entries with restricted access to their own databases.

Update / Solution I ended up using Go's built in Context by Copying a session and using it anywhere I need to do any CRUD ops

Something like:

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
}

And then use it in a HandlerFunc, example /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% response time decrease over the original method I experimented with.

  • 写回答

1条回答 默认 最新

  • dongyun6835 2017-02-14 10:25
    关注

    Hypothetically speaking is not a good practice because:

    1. The database logic is scattered among several packages.
    2. It's difficult to test
    3. You can't apply DI (mainly it will be hard to maintain the code)

    Replying to your questions:

    1. Yes is feasible BUT you will not use the connection pool inside them go package (take a look to the code here if you want know more about Connection Pool)
    2. A better way is to create a global variable that contains the database connection and close when the application is going to stop (and not close the connection every request)
    3. How do I ensure the session is only closed when the request has complete<- you should checkout the answer fro your db query and then close the connection (but I don't recommend to close the connection after a request because you'll need to open again for another request and close again etc...)
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 socket通信实现多人聊天室疑惑
  • ¥15 DEV-C++编译缺失
  • ¥33 找熟练码农写段Pyhthon程序
  • ¥100 怎么让数据库字段自动更新
  • ¥15 antv g6 力导向图布局
  • ¥15 quartz框架,No record found for selection of Trigger with key
  • ¥15 锅炉建模+优化算法,遗传算法优化锅炉燃烧模型,ls-svm会搞,后面的智能算法不会
  • ¥20 MATLAB多目标优化问题求解
  • ¥15 windows2003服务器按你VPN教程设置后,本地win10如何连接?
  • ¥15 求一阶微分方程的幂级数