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 iOS绕地区网络检测
  • ¥15 python验证码滑块图像识别
  • ¥15 根据背景及设计要求撰写设计报告
  • ¥15 QT6颜色选择对话框显示不完整
  • ¥20 能提供一下思路或者代码吗
  • ¥15 用twincat控制!
  • ¥15 请问一下这个运行结果是怎么来的
  • ¥15 单通道放大电路的工作原理
  • ¥30 YOLO检测微调结果p为1
  • ¥15 DS18B20内部ADC模数转换器