87098a9180
- 在 HoTimeDB 中新增 testMu 互斥锁,确保 testTx 的串行访问,解决并发冲突问题 - 在 BeginTestTx 中初始化 testMu,确保测试事务的安全性 - 在 HoTimeCache 中新增 DisableDbCache 方法,测试模式下禁用 DB 和 Redis 缓存,避免锁等待超时 - 更新 Select 方法,确保在 testTx 激活时跳过缓存逻辑,提升测试稳定性 - 优化 Swagger 生成逻辑,支持模块化输出和导航页生成 - 移除冗余的调试日志代码,提升代码整洁性
160 lines
3.3 KiB
Go
160 lines
3.3 KiB
Go
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
|
||
}
|