package hotime import ( "sync" . "code.hoteas.com/golang/hotime/cache" . "code.hoteas.com/golang/hotime/common" ) // session对象 type SessionIns struct { *HoTimeCache SessionId string Map ContextBase mutex sync.RWMutex } // set 保存 session 到缓存,必须在锁内调用或传入深拷贝的 map func (that *SessionIns) setWithCopy() { // 深拷贝 Map 防止并发修改 that.mutex.RLock() copyMap := make(Map, len(that.Map)) for k, v := range that.Map { copyMap[k] = v } that.mutex.RUnlock() that.HoTimeCache.Session(HEAD_SESSION_ADD+that.SessionId, copyMap) } func (that *SessionIns) Session(key string, data ...interface{}) *Obj { that.mutex.Lock() if that.Map == nil { that.getWithoutLock() } that.mutex.Unlock() if len(data) != 0 { that.mutex.Lock() if data[0] == nil { delete(that.Map, key) } else { that.Map[key] = data[0] } that.mutex.Unlock() // 使用深拷贝版本保存,避免并发问题 that.setWithCopy() return &Obj{Data: nil} } that.mutex.RLock() result := &Obj{Data: that.Map.Get(key)} that.mutex.RUnlock() return result } // SessionsSet 批量设置session字段,只触发一次数据库写入 // 用法:that.SessionsSet(Map{"key1": value1, "key2": value2, ...}) // 性能优化:设置N个字段只触发1次数据库写入(而非N次) func (that *SessionIns) SessionsSet(data Map) { if len(data) == 0 { return } that.mutex.Lock() if that.Map == nil { that.getWithoutLock() } // 批量设置所有字段 for key, value := range data { if value == nil { delete(that.Map, key) } else { that.Map[key] = value } } that.mutex.Unlock() // 只触发一次数据库写入 that.setWithCopy() } // SessionsDelete 批量删除session字段,只触发一次数据库写入 // 用法:that.SessionsDelete("key1", "key2", ...) func (that *SessionIns) SessionsDelete(keys ...string) { if len(keys) == 0 { return } that.mutex.Lock() if that.Map == nil { that.getWithoutLock() } // 批量删除所有字段 for _, key := range keys { delete(that.Map, key) } that.mutex.Unlock() // 只触发一次数据库写入 that.setWithCopy() } // SessionsGet 批量获取session字段 // 用法:result := that.SessionsGet("key1", "key2", ...) // 返回 Map,key 为字段名,value 为字段值(不存在的 key 不包含在结果中) func (that *SessionIns) SessionsGet(keys ...string) Map { if len(keys) == 0 { return Map{} } that.mutex.Lock() if that.Map == nil { that.getWithoutLock() } that.mutex.Unlock() result := make(Map, len(keys)) that.mutex.RLock() for _, key := range keys { if value, exists := that.Map[key]; exists { result[key] = value } } that.mutex.RUnlock() return result } // getWithoutLock 内部使用,调用前需要已持有锁 func (that *SessionIns) getWithoutLock() { that.Map = that.HoTimeCache.Session(HEAD_SESSION_ADD + that.SessionId).ToMap() if that.Map != nil { return } that.Map = Map{} // 保存时也需要深拷贝 copyMap := make(Map, len(that.Map)) for k, v := range that.Map { copyMap[k] = v } that.HoTimeCache.Session(HEAD_SESSION_ADD+that.SessionId, copyMap) } func (that *SessionIns) get() { that.mutex.Lock() defer that.mutex.Unlock() that.getWithoutLock() } func (that *SessionIns) Init(cache *HoTimeCache) { that.mutex = sync.RWMutex{} that.HoTimeCache = cache }