2014-10-26 119 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