feat(app): 提供通用缓存
This commit is contained in:
122
pkg/cache/common/common.go
vendored
Normal file
122
pkg/cache/common/common.go
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"gitea.ddegame.cn/open/servicebase/pkg/cache"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBCacheFetcher[T any] func(fieldKey string) (*T, error)
|
||||||
|
type DBCacheFetcherMany[T any] func(fieldKeys []string) (map[string]*T, error)
|
||||||
|
|
||||||
|
func GetOrCacheOne[T any](cli *redis.Client, hashKey string, fieldKey string, dbFetcher DBCacheFetcher[T]) (*T, error) {
|
||||||
|
if len(fieldKey) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var cachedStr string
|
||||||
|
var err error
|
||||||
|
if cachedStr, err = cli.HGet(cache.Ctx(), hashKey, fieldKey).Result(); err != nil && !errors.Is(err, redis.Nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var model *T
|
||||||
|
if len(cachedStr) > 0 {
|
||||||
|
model = new(T)
|
||||||
|
if err = json.Unmarshal([]byte(cachedStr), model); err == nil {
|
||||||
|
return model, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if model, err = dbFetcher(fieldKey); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if model == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
bytes, marshalErr := json.Marshal(model)
|
||||||
|
if marshalErr != nil {
|
||||||
|
return model, nil
|
||||||
|
}
|
||||||
|
_, _ = cli.HSet(cache.Ctx(), hashKey, fieldKey, string(bytes)).Result()
|
||||||
|
return model, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOrCacheMany[T any](cli *redis.Client, hashKey string, fieldKeyList []string, dbFetcherMany DBCacheFetcherMany[T]) ([]*T, error) {
|
||||||
|
if len(fieldKeyList) == 0 {
|
||||||
|
return make([]*T, 0), nil
|
||||||
|
}
|
||||||
|
finalResults := make([]*T, len(fieldKeyList))
|
||||||
|
missingKeysMap := make(map[string]int)
|
||||||
|
missingKeysList := make([]string, 0)
|
||||||
|
values, err := cli.HMGet(cache.Ctx(), hashKey, fieldKeyList...).Result()
|
||||||
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i, fieldKey := range fieldKeyList {
|
||||||
|
value := values[i]
|
||||||
|
if value == nil {
|
||||||
|
missingKeysMap[fieldKey] = i
|
||||||
|
missingKeysList = append(missingKeysList, fieldKey)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cachedStr, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
missingKeysMap[fieldKey] = i
|
||||||
|
missingKeysList = append(missingKeysList, fieldKey)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
model := new(T)
|
||||||
|
if jsonErr := json.Unmarshal([]byte(cachedStr), model); jsonErr == nil {
|
||||||
|
finalResults[i] = model
|
||||||
|
} else {
|
||||||
|
missingKeysMap[fieldKey] = i
|
||||||
|
missingKeysList = append(missingKeysList, fieldKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missingKeysList) == 0 {
|
||||||
|
return finalResults, nil
|
||||||
|
}
|
||||||
|
dbModelsMap, err := dbFetcherMany(missingKeysList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cacheMap := make(map[string]any)
|
||||||
|
for fieldKey, model := range dbModelsMap {
|
||||||
|
originalIndex, found := missingKeysMap[fieldKey]
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
finalResults[originalIndex] = model
|
||||||
|
if model != nil {
|
||||||
|
if bytes, marshalErr := json.Marshal(model); marshalErr == nil {
|
||||||
|
cacheMap[fieldKey] = string(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(cacheMap) > 0 {
|
||||||
|
_, _ = cli.HSet(cache.Ctx(), hashKey, cacheMap).Result()
|
||||||
|
}
|
||||||
|
return finalResults, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelCacheFields(cli *redis.Client, hashKey string, fieldKeyList ...string) error {
|
||||||
|
if len(fieldKeyList) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := cli.HDel(cache.Ctx(), hashKey, fieldKeyList...).Result()
|
||||||
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DelCacheHash(cli *redis.Client, hashKey string) error {
|
||||||
|
if len(hashKey) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := cli.Del(cache.Ctx(), hashKey).Result()
|
||||||
|
if err != nil && !errors.Is(err, redis.Nil) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user