2016-09-22 138 views
0

我在後端使用golang,mongodb是我的數據庫。 我想將我的web應用程序的用戶會話(在登錄和註銷之間)存儲在mongodb中以進行持久化。由於提供者僅適用於mysql而不適用於mongodb,因此我編輯它以支持mongodb.But,當我嘗試使用它即時得到無效的內存地址或零指針解除引用。 的代碼如下,請,如果有什麼更好的辦法來編碼,請讓我know.Thanks在mongodb golang中保存會話

type (
    SessionStore struct { 
     c  *mgo.Session 
     sid string 
     lock sync.RWMutex 
     values map[interface{}]interface{} 
    } 
) 

var mgopder = &Provider{} 

func (st *SessionStore) Set(key, value interface{}) error { 
    st.lock.Lock() 
    defer st.lock.Unlock() 
    st.values[key] = value 
    return nil 
} 

// Get value from mongodb session 
func (st *SessionStore) Get(key interface{}) interface{} { 
    st.lock.RLock() 
    defer st.lock.RUnlock() 
    if v, ok := st.values[key]; ok { 
     return v 
    } 
    return nil 
} 

// Delete value in mongodb session 
func (st *SessionStore) Delete(key interface{}) error { 
    st.lock.Lock() 
    defer st.lock.Unlock() 
    delete(st.values, key) 
    return nil 
} 

// Flush clear all values in mongodb session 
func (st *SessionStore) Flush() error { 
    st.lock.Lock() 
    defer st.lock.Unlock() 
    st.values = make(map[interface{}]interface{}) 
    return nil 
} 

// SessionID get session id of this mongodb session store 
func (st *SessionStore) SessionID() string { 
    return st.sid 
} 

// SessionRelease save mongodb session values to database. 
// must call this method to save values to database. 
func (st *SessionStore) SessionRelease(w http.ResponseWriter) { 
    defer st.c.Close() 
    b, err := session.EncodeGob(st.values) 
    if err != nil { 
     return 
    } 
    st.c.DB("Employee").C("Sessions").Update(nil, bson.M{"$set": bson.M{ 
     "session_data": b, 
     "session_expiry": time.Now().Unix(), 
     "session_key": st.sid, 
    }, 
    }, 
    ) 

    /*st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?", 
    b, time.Now().Unix(), st.sid)*/ 
} 

type Provider struct { 
    maxlifetime int64 
    savePath string 
    Database string 
} 

// connect to mongodb 
func (mp *Provider) connectInit() *mgo.Session { 
    ds, err := mgo.Dial("Employee") 
    if err != nil { 
     return nil 
    } 
    return ds 
} 

// SessionInit init mongodb session. 
// savepath is the connection string of mongodb 
func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error { 
    mp.maxlifetime = maxlifetime 
    mp.savePath = savePath 
    mp.Database = "Employee" 
    return nil 
} 

// SessionRead get mysql session by sid 
func (mp *Provider) SessionRead(sid string) (session.Store, error) { 
    var sessiondata []byte 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB(mp.Database).C("Session") 
    err := c.Find(bson.M{ 
     "session_key": sid, 
    }).Select(bson.M{"session_data": 1}).All(&sessiondata) 
    if err != nil { 
     if err.Error() == "not found" { 
      c.Insert(bson.M{ 
       "session_key": sid, 
       "session_data": " ", 
       "session_expiry": time.Now().Unix(), 
      }) 
     } 
    } 

    var kv map[interface{}]interface{} 
    if len(sessiondata) == 0 { 
     kv = make(map[interface{}]interface{}) 
    } else { 
     kv, err = session.DecodeGob(sessiondata) 
     if err != nil { 
      return nil, err 
     } 
    } 
    rs := &SessionStore{c: ds, sid: sid, values: kv} 
    return rs, nil 
} 

// SessionExist check mongodb session exist 
func (mp *Provider) SessionExist(sid string) bool { 
    var sessiondata []byte 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB("Employee").C("Sessions") 
    err := c.Find(bson.M{ 
     "session_key": sid, 
    }).Select(bson.M{ 
     "session_data": 1, 
    }).One(&sessiondata) 
    if err != nil { 
     if err.Error() == "not found" { 
      return false 
     } 
    } 
    return true 

} 

// SessionRegenerate generate new sid for mysql session 
func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { 
    var sessiondata []byte 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB("Employee").C("Sessions") 
    err := c.Find(bson.M{ 
     "session_key": oldsid, 
    }).Select(bson.M{ 
     "session_data": 1, 
    }).One(&sessiondata) 
    if err != nil { 
     if err.Error() == "not found" { 
      c.Insert(bson.M{ 
       "sessoin_key": oldsid, 
       "session_data": " ", 
       "session_expiry": time.Now().Unix(), 
      }) 
     } 
    } 
    /* row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid) 

     err := row.Scan(&sessiondata) 

    c.Update(bson.M{"sessoin_key": oldsid}, bson.M{ 
     "$set": bson.M{ 
      "session_key": sid, 
     }, 
    }) 
    /*c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid) 
    */ 
    var kv map[interface{}]interface{} 
    if len(sessiondata) == 0 { 
     kv = make(map[interface{}]interface{}) 
    } else { 
     kv, err = session.DecodeGob(sessiondata) 
     if err != nil { 
      return nil, err 
     } 
    } 
    rs := &SessionStore{c: ds, sid: sid, values: kv} 
    return rs, nil 
} 

// SessionDestroy delete mysql session by sid 
func (mp *Provider) SessionDestroy(sid string) error { 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB("Employee").C("Sessions") 
    c.Remove(bson.M{ 
     "session_key": sid, 
    }) 
    return nil 
} 

// SessionGC delete expired values in mysql session 
func (mp *Provider) SessionGC() { 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB("Employee").C("Sessions") 
    c.Remove(bson.M{ 
     "session_expiry": bson.M{ 
      "$lt": time.Now().Unix() - mp.maxlifetime, 
     }, 
    }) 
return 
} 

// SessionAll count values in mysql session 
func (mp *Provider) SessionAll() int { 
    var total int 
    ds := mp.connectInit() 
    defer ds.Close() 
    c := ds.DB("Employee").C("Sessions") 
    total, err := c.Count() 

    if err != nil { 
     return 0 
    } 
    return total 
} 

func init() { 
    session.Register("mongodb", mgopder) 
} 

錯誤:

panic: runtime error: invalid memory address or nil pointer dereference 
     panic: runtime error: invalid memory address or nil pointer dereference 
[signal 0xc0000005 code=0x1 addr=0x0 pc=0x6db254] 

goroutine 6 [running]: 
panic(0xa2f560, 0xc0820080b0) 
     C:/Go/src/runtime/panic.go:481 +0x3f4 
gopkg.in/mgo%2ev2.(*Session).Close(0x0) 
     C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:1612 +0x144 
panic(0xa2f560, 0xc0820080b0) 
     C:/Go/src/runtime/panic.go:443 +0x4f7 
gopkg.in/mgo%2ev2.(*Session).acquireSocket(0x0, 0xc082290000, 0x0, 0x0, 0x0) 
     C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4409 +0x4ba 
gopkg.in/mgo%2ev2.(*Collection).writeOp(0xc082279f30, 0x8feb80, 0xc082326060, 0xc082326001, 0x0, 0x0, 0x0) 
     C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:4604 +0xe7 
gopkg.in/mgo%2ev2.(*Collection).Remove(0xc082279f30, 0x9d4700, 0xc082326030, 0x0, 0x0) 
     C:/Projects/Go/src/gopkg.in/mgo.v2/session.go:2586 +0x15c 
sample/models.(*Provider).SessionGC(0xe2f5a0) 
     C:/Projects/Go/src/sample/models/model.go:234 +0x3dc 
github.com/astaxie/beego/session.(*Manager).GC(0xc082258b20) 
     C:/Projects/Go/src/github.com/astaxie/beego/session/session.go:271 +0x48 
created by github.com/astaxie/beego.registerSession 
     C:/Projects/Go/src/github.com/astaxie/beego/hooks.go:68 +0x31d 

回答

0

不知道你的代碼,這裏的一個樣本打包文件,創建一個會話去MongoDB並使用它。

package mydb 

import (
    "fmt" 
    "os" 

    "gopkg.in/mgo.v2" 
    "gopkg.in/mgo.v2/bson" 
) 

var Db *mgo.Session 

type DbLink struct { 
    DbName string 
} 

func NewDbSession(url string) { 
    var e error 

    Db, e = mgo.Dial(url) 

    if e != nil { 
     panic(e) 
     os.Exit(-1) 
    } 
} 

然後在你的主包:

package main 

import (
    "fmt" 
    "os" 

    "mydb" 
) 

func main() { 
    // <user> the user to access the db 
    // <pwd> the database user password 
    // <host> hostname or ip address of the database server (localhost i.e.) 
    // <port> the port where the database server is listening (usually 27016). 
    mydb.NewDbSession("mongodb://<user>:<pwd>@<host>:<port>/?authSource=<db_name>") 

    session := mydb.Db.Copy() 
    defer session.Close() 

    col := session.DB("my_db_schema").C("my_collection_name") 

    // row is a list of struct depends on collection 
    err := col.Find(bson.M{"field_name": "value"}).All(&row) 
    if err != nil { 
     fmt.Printf("%s\n", err) 
    } 

} 

這是一個非常簡單的例子,應該幫助您開始。

考慮到MongoDB中這是非常不同的從MySQL,因爲它是一個的NoSQL模式少數據庫管理系統。

有關詳細信息,請參閱文檔mgo包。

你的用戶會話的結構有一些問題:

type SessionStore struct { 
    c  *mgo.Session 
    sid string 
    lock sync.RWMutex 
    values map[interface{}]interface{} 
} 

首先,你必須用大寫字母來導出密鑰。

例如,而不是Ç你應該使用Ç等與希德鎖定價值觀

type SessionStore struct { 
    C  *mgo.Session    `json:"C" bson:"c"` 
    Sid string      `json:"Sid" bson:"sid,omitempty"` 
    Lock sync.RWMutex    `json:"Lock" bson:"lock,omitempty"` 
    Values map[interface{}]interface{} `json:"Values" bson:"values,omitempty"` 
} 

我不認爲這將與指針工作。

+0

我很抱歉,需要在mongodb中存儲用戶會話(在我的web應用程序的登錄和註銷之間)以及獨特的會話ID ...請讓我知道如何去做。謝謝.... –

+0

@RajeshKumar我更新了我的答案,請看看 –

+0

感謝mario,.Changed it.But還面臨同樣的錯誤problem.thanks ... –

0

這是我通常做的。

package mongo 

import (
    "time" 

    "gopkg.in/mgo.v2" 
) 

// DataStore containing a pointer to a mgo session 
type DataStore struct { 
    Session *mgo.Session 
} 

// ConnectToTagserver is a helper method that connections to pubgears' tagserver 
// database 
func (ds *DataStore) ConnectToTagserver() { 
    mongoDBDialInfo := &mgo.DialInfo{ 
     Addrs: []string{"some IP"}, 
     Timeout: 60 * time.Second, 
     Database: "some db", 
    } 
    sess, err := mgo.DialWithInfo(mongoDBDialInfo) 
    if err != nil { 
     panic(err) 
    } 
    sess.SetMode(mgo.Monotonic, true) 
    ds.Session = sess 
} 

// Close is a helper method that ensures the session is properly terminated 
func (ds *DataStore) Close() { 
    ds.Session.Close() 
} 

然後在我的模型包我做這樣的事情

package models 

import (
    "./mongo" 
    "gopkg.in/mgo.v2/bson" 
) 

// AdSize represents the data object stucture that is returned by querying 
// mongo's account collection 
type AdSize struct { 
    ID  bson.ObjectId `bson:"_id,omitempty"` 
    Providers []string  `bson:"providers"` 
    Size  string  `bson:"size"` 
} 

// GetAllAdsizes is a helper function designed to retrieve all the objects in the 
// adsize collection 
func GetAllAdsizes() ([]AdSize, error) { 
    ds := mongo.DataStore{} 
    ds.ConnectToTagserver() 
    defer ds.Close() 
    adSizes := []AdSize{} 
    adSizeCollection := ds.Session.DB("some database").C("some collection") 
    err := adSizeCollection.Find(bson.M{}).Sort("name").All(&adSizes) 
    return adSizes, err 
} 

所以我創造了蒙戈文件會話包裝,然後在一些路線創建的模型文件中的會話對象,然後最後我調用GetAllAdsizes()方法處理我的mongo會話。會話保持活動狀態,直到GetAllAdsizes()方法結束爲止,因爲它在延遲上被關閉。然而,像這樣的東西可以修改,在那裏你處理所有的用戶東西,然後關閉會話,如果用戶註銷。在這裏看看Best practice to maintain a mgo session,你可以看到類似的邏輯。