[英]save session in mongodb golang
我在后端使用golang,而mongodb是我的数据库。 我想将我的Web应用程序的用户会话(登录和注销后)存储在mongodb中以实现持久性。由于存在仅适用于mysql而不适用于mongodb的提供程序,因此我对其进行了编辑以支持mongodb。但是当我尝试使用它时我正在获取无效的内存地址或nil指针取消引用。 代码如下,如果有更好的编码方法,请告诉我。谢谢
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
这是我通常所做的。
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文件中创建了一个会话对象,最后在某些路由文件中调用了处理我的mongo会话的方法GetAllAdsizes()。 该会话将保持活动状态,直到GetAllAdsizes()方法的结尾,因为该会话在延迟后关闭。 但是,可以修改类似的内容,在此您可以处理所有用户资料,然后在用户注销时关闭会话。 在此处还可以查看维护mgo会话的最佳实践 ,在这里您可以看到类似的逻辑类型。
不确定您的代码,这里是一个打包文件的示例,该文件在go中创建了与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{}
}
首先,您必须使用大写字母导出密钥。
例如,您应该使用C ,而不是c ,以此类推,例如Sid , Lock和Values 。
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"`
}
我认为这不适用于指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.