基于不同的业务场景,我们可以选择设计一个符合自己业务场景的缓存。
对于我需要的而言,我需要是
1、能够定时从数据库中自动加载数据。
2、支持并发安全
3、支持过期淘汰
4、便于扩展、较为通用
接口定义
// CacheInterface 提供对于缓存 get set del
type CacheInterface interface {
SetVal(key string, response *Value) error
GetVal(key string) *Value
DelVal(key string)
loadFunc(ctx context.Context, cache *ICache)
}
// cache 实现
//ICache
// cache 缓存
// callback 执行函数
// executeInterval 定期刷新时间
// key 唯一key
// params 请求参数
// reTry 执行异常重试次数
// reTryInterVal 执行异常重试间隔
// reSetCountDay 统计重置函数更新的次数,用来判断改数据的操作是否频繁 包含day、week、month 维度
// reSetCountWeek week 维度次数统计
// reSetCountMonth 月统计维度
type ICache struct {
callback CallBackFunc
executeInterval time.Duration
key string
params map[string]interface{}
reTry int
reTryInterval time.Duration
reSetCountDay int
reSetCountWeek int
reSetCountMonth int
}
//构造器
func NewCache() *ICache {
return &ICache{}
}
// CallBackFunc 执行回调函数
type CallBackFunc func(map[string]interface{}) *Value
var ErrLargeKey = errors.New("the key is larger than 65535")
var maxKeyLen = 65535
var reTry = 3
var reTryInterval = time.Second * 10
func Set(request *SingleRequest) error {
return NewCache().SetVal(request.Key, request.Value)
}
func (c *ICache) SetVal(key string, response *Value) error {
if len(key) > maxKeyLen {
return ErrLargeKey
}
setVal(key, response)
return nil
}
func Get(key string) *Value {
return getVal(key)
}
func Del(key string) {
delVal(key)
return
}
func (c *ICache) GetVal(key string) *Value {
return getVal(key)
}
func (c *ICache) DelVal(key string) {
delVal(key)
return
}
// LoadFunc 提供加载
func LoadFunc(request *LoadRequest) {
ctx := context.Background()
if request.ReTry == 0 {
request.ReTry = reTry
}
if request.ReTryInterval == 0 {
request.ReTryInterval = reTryInterval
}
cache := &ICache{
callback: request.Callback,
executeInterval: request.TTL,
key: request.Key,
params: request.CallBackParams,
reTry: request.ReTry,
reTryInterval: request.ReTryInterval,
reSetCountDay: request.ReSetCountDay,
reSetCountWeek: request.ReSetCountWeek,
reSetCountMonth: request.ReSetCountMonth,
}
go cache.loadFunc(ctx, cache)
}
func (c *ICache) loadFunc(ctx context.Context, cache *ICache) {
defer func() {
if x := recover(); x != nil {
log.Println("x--->", string(debug.Stack()))
}
}()
SyncLoop:
for {
res := cache.callback(cache.params)
// fmt.Println("totalCount-->", res.TotalCount, "one-->", res.ResultOne, "list-->", res.ResultList)
temp := 3
var err error
for temp > 0 {
res = cache.callback(cache.params)
if res.error == nil {
break
}
err = res.error
time.Sleep(time.Second * 3)
fmt.Println("每隔3秒重试一次:", cache.key)
temp--
}
if temp == 0 && err != nil {
ctx.Done()
fmt.Println("重试失败,结束重试!!!", err.Error())
break
}
if res.error != nil {
log.Printf("查询失败")
ctx.Done()
break
}
if err := c.SetVal(cache.key, res); err != nil {
ctx.Done()
break
}
select {
case <-time.After(cache.executeInterval):
log.Default().Printf("%s", "下一次循环")
case <-ctx.Done():
log.Printf("协程处理失败")
break SyncLoop
}
}
}
func setVal(key string, response *Value) {
cacheLock.Lock()
LocalCache[key] = response
cacheLock.Unlock()
}
func getVal(key string) *Value {
return LocalCache[key]
}
func delVal(key string) {
cacheLock.Lock()
delete(LocalCache, key)
cacheLock.Unlock()
}
protol
// LoadRequest 缓存设置包结构
// CallBack 执行加载函数
// TTL 过期时间
// Key 缓存key
// CallBackParams callback 请求参数
// ReTry 重试次数
// ReTryInterval 重试时间间隔
// ReTryInterVal 执行异常重试间隔
// ReSetCountDay 统计重置函数更新的次数,用来判断改数据的操作是否频繁 包含day、week、month 维度
// ReSetCountWeek week 维度次数统计
// ReSetCountMonth 月统计维度
type LoadRequest struct {
Callback CallBackFunc
TTL time.Duration
Key string
CallBackParams map[string]interface{}
ReTry int
ReTryInterval time.Duration
ReSetCountDay int
ReSetCountWeek int
ReSetCountMonth int
}
// SingleRequest 不需要定时加载,直接set 缓存
type SingleRequest struct {
Key string `json:"key"`
Value *Value `json:"value"`
TTL time.Duration `json:"ttl"`
}
// Value 设置缓存结构体
type Value struct {
TotalCount int64
ResultList []map[string]interface{}
ResultOne map[string]interface{}
error error
}
test 测试
func TestSetAndGet(t *testing.T) {
err := Set(&SingleRequest{Key: "key1", Value: &Value{TotalCount: 1, ResultList: nil, ResultOne: map[string]interface{}{"1": 1}, error: nil}})
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("key1缓存设置成功")
res := NewCache().GetVal("key1")
fmt.Println("key1最终结果", res.TotalCount, " ", res.ResultOne, " ", res.ResultList)
}
func TestLoad(t *testing.T) {
LoadFunc(&LoadRequest{
Callback: NewPerson().QueryPersonInfo,
Key: "person",
})
res := Get("person")
fmt.Println("person--------->",res)
time.Sleep(1 * time.Second)
res = Get("person")
fmt.Println("person--------->",res)
}
type Person struct {
}
func NewPerson() *Person {
return &Person{}
}
func (person *Person) QueryPersonInfo(params map[string]interface{}) *Value {
//db.Query
p := map[string]interface{}{"id": 1, "name": "zdm", "age": 18, "sex": "man"}
return &Value{TotalCount: 1, ResultOne: p}
}
测试效果
因篇幅问题不能全部显示,请点此查看更多更全内容