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...)
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥15 统计大规模图中的完全子图问题
  • ¥15 使用LM2596制作降压电路,一个能运行,一个不能
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错
  • ¥20 @microsoft/fetch-event-source 流式响应问题
  • ¥15 ogg dd trandata 报错
  • ¥15 高缺失率数据如何选择填充方式