2014-10-26 120 views
23

我目前使用氧化镁与LIB的web应用程序的mongodb一个一个的MgO会议,但我不知道如果我在使用它的方式,是很好的一个..最佳实践,以保持

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") 
) 

我初始化了数据库会话并创建了获取集合和文档值的变量, 因此,当我需要查询集合时,我使用该变量创建它。

就像是:

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 
    } 
} 

那么,有没有一个最佳做法或这个人是很好..? 谢谢

+0

最好的做法是使用函数来设置数据库会话,而不是变量声明。使用函数的一个原因是您可以处理来自拨号的错误返回。对于UserExist,我将使用[结果集中的文档数量](http://godoc.org/gopkg.in/mgo.v2#Query.Count)来确定文档是否存在。没有必要获取实际的文档。 – 2014-10-26 16:31:15

+0

感谢您提供UserExist功能的提示!但有了初始化会话连接的功能,我可以在db包中使用“func init()”来完成它,并为返回会话分配db和collection的全局变量?我只是不知道如何保持我打开数据库的会话,没有每次我需要它时,“mgo.Dial()”,也有我的数据库和集合已经初始化... – JonathanChaput 2014-10-26 17:00:33

回答

47

我建议不要使用这样的全局会话。相反,您可以创建一个负责所有数据库交互的类型。例如:

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驱动程序表现很好,因为会话在内部被缓存并被重用/维护。每个会话在使用时还将由一个独立的套接字支持,并且可以配置独立的设置,并且还具有独立的错误处理。如果您使用单个全局会话,则这些问题最终必须处理。

+10

有_many_理由像你说的那样有这样的设置。 'session.Copy()'调用尤其重要,对于在Go中使用Mongo驱动程序的人来说,这并不够强调,因为它允许驱动程序充分利用并发性。但是,然后 - 你知道所有关于..:P +1 – 2014-10-26 22:51:13

+0

因此,你启动一个初始的全球会议,然后复制它的每一个请求? – collinglass 2015-03-05 01:59:52

+1

主会议,是的。在“全球变量”这个词的意义上,它不一定是全球性的。 – 2015-03-05 16:49:55

2

虽然不直接回答你的问题,关于mgo会话检查你必须使用延迟/恢复,因为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() 
} 
+0

您可以使用没有此功能的恢复中间件恢复您的处理程序。 – 2017-07-23 21:21:02

+0

@inanc中间件是如何完成这个的? DataStore.Ping? – Zamicol 2017-07-24 22:19:09

+0

当它惊慌失措时,查看错误消息,然后重新连接。 – 2017-07-24 22:22:31

1

一起去1.7,对Web服务器处理蒙戈会议最惯用的方法是使用新的标准库包context编写可以附加defer session.Close()每当请求上下文中完成()中间件被称为。所以你不需要记住关闭

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)) 
     }) 
    } 
+2

上下文并不意味着用于像mongo会话那样的长时间的事情。这是一种臭型反模式。 – 2017-07-23 21:21:41

+0

@InancGumus哪种方法是处理mongo会话的最佳方法?我在使用上下文和mongo会话时看到了很多例子。 – UnNatural 2018-02-15 16:05:21

+0

您可以从注入的结构成员中复制会话,例如向下行。 – 2018-02-16 19:07:02