Лучшая практика для поддержания сеанса mgo
В настоящее время я использую mongodb с mgo lib для веб-приложения, но я не уверен, способ, которым я его использую, хороший.
package db
import (
"gopkg.in/mgo.v2"
)
const (
MongoServerAddr = "192.168.0.104"
RedisServerAddr = "192.168.0.104"
)
var (
MongoSession, err = mgo.Dial(MongoServerAddr)
MDB = MongoSession.DB("message")
MCol = MDB.C("new")
MSav = MDB.C("save")
UDB = MongoSession.DB("account")
UCol = UDB.C("user")
)
Я запускаю сеанс db и создаю переменные, которые берут значение коллекции и документа,
поэтому, когда мне нужно запросить коллекцию, я использую переменную, чтобы сделать ее.
Вроде:
func UserExist(username string) bool {
user := Users{}
err := db.UCol.Find(bson.M{"username": username}).One(&user)
if err != nil {
return false
} else {
return true
}
}
Итак, есть ли лучшая практика, или это хорошо.?
Благодаря
Ответы
Ответ 1
Я предлагаю не использовать такой глобальный сеанс. Вместо этого вы можете создать тип, отвечающий за взаимодействие с базой данных. Например:
type DataStore struct {
session *mgo.Session
}
func (ds *DataStore) ucol() *mgo.Collection { ... }
func (ds *DataStore) UserExist(user string) bool { ... }
В этом дизайне много преимуществ. Важным является то, что он позволяет одновременно выполнять несколько сеансов в полете, поэтому, если у вас есть обработчик http, например, вы можете создать локальный сеанс, который поддерживается независимым сеансом только для этого одного запроса:
func (s *WebSite) dataStore() *DataStore {
return &DataStore{s.session.Copy()}
}
func (s *WebSite) HandleRequest(...) {
ds := s.dataStore()
defer ds.Close()
...
}
В этом случае драйвер mgo хорошо себя ведет, поскольку сеансы внутренне кэшируются и повторно используются/поддерживаются. Каждый сеанс также будет поддерживаться независимым сокетом во время использования и может иметь независимые настройки, а также будет иметь независимую обработку ошибок. Это проблемы, с которыми вам придется столкнуться, если вы используете одну глобальную сессию.
Ответ 2
Если вы не ответите на свой вопрос напрямую, в отношении проверки сеанса mgo вы должны использовать defer/recover, поскольку mgo вызывает (даже mgo.session.Ping) панику. Насколько я могу судить, нет другого способа проверить состояние сеанса mgo (mgo godocs). Вы можете использовать предложение Gustavo Niemeyer и добавить метод по типу DataStore
.
func (d *DataStore) EnsureConnected() {
defer func() {
if r := recover(); r != nil {
//Your reconnect logic here.
}
}()
//Ping panics if session is closed. (see mgo.Session.Panic())
d.Ping()
}
Ответ 3
С переходом 1.7 самый идиоматический способ обработки сеанса mongo на веб-сервере - использовать новый стандартный пакет библиотеки context
для написания промежуточного программного обеспечения, которое может присоединить defer session.Close()
к каждому вызову контекста запроса Done(), Поэтому вам не нужно запоминать, чтобы закрыть
AttachDeviceCollection = func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
db, err := infra.Cloner()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
collection, err := NewDeviceCollection(db)
if err != nil {
db.Session.Close()
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
ctx := context.WithValue(r.Context(), DeviceRepoKey, collection)
go func() {
select {
case <-ctx.Done():
collection.Session.Close()
}
}()
next.ServeHTTP(w, r.WithContext(ctx))
})
}