我在后端使用golang而mongodb是我的数据库。 我希望将我的web应用程序的用户会话(登录和注销)存储在mongodb中以用于持久性。因为有提供程序仅适用于mysql而不是mongodb,我编辑它以支持mongodb.But当我尝试使用它时我得到无效的内存地址或无指针取消引用。 代码如下,如果有更好的编码方式,请告诉我。谢谢
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 :(得分:1)
这就是我通常做的事情。
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
}
所以我在mongo文件中创建了一个会话包装器,然后在models文件中创建了一个会话对象,最后在一些路由文件中我调用了GetAllAdsizes()方法,该方法处理了我的mongo会话。会话保持活动直到GetAllAdsizes()方法结束,因为它在延迟时关闭。但是,可以修改这样的内容,您可以处理所有用户的内容,然后在用户注销时关闭会话。还可以看看Best practice to maintain a mgo session,在那里你可以看到类似的逻辑。
答案 1 :(得分:0)
不确定您的代码,下面是一个包文件示例,该文件在go中创建了一个mongodb会话并使用它。
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)
}
}
然后在你的主要包裹中:
type SessionStore struct {
c *mgo.Session
sid string
lock sync.RWMutex
values map[interface{}]interface{}
}
这是一个非常简单的例子,可以帮助你开始。
考虑到MongoDB与MySQL非常不同,因为它是 NoSQL 和架构数据库管理系统。
有关详细信息,请参阅 mgo 包的文档。
您的用户会话结构存在一些问题:
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"`
}
首先,您必须使用大写字母来导出密钥。
例如,您应该使用 C 代替 c ,依此类推 Sid , Lock 和< EM>值
ArrayMap
我认为这不会适用于指针。