代码拉取完成,页面将自动刷新
package gxdb
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"time"
"github.com/go-redis/redis/v7"
"github.com/unknwon/com"
"gitee.com/atcharles/grow/Library/gtools"
)
//redis 缓存方式=> hashMap
//#####参与缓存的字段,必须是永远不会被修改的字段#####
/*
检查是否实现了复合索引接口
对于没有实现接口的对象,不做缓存
db:1
key: /h/tableName
field: 遍历columns,k:v/k:v ...;
如果实现了接口而columns len==0,
则通过反射查询对象的tag 包含 pk 的field,field=该fieldValue
value: 对象的数据库数据的json序列化字符串
*/
//cache redis constant
const (
RedisDBCache = 1
)
type cacheRedis struct {
has bool
bean interface{}
value *reflect.Value
cmiList []*CompoundIndex
fields []string
db *xdb
}
func (r *cacheRedis) bindGet() (err error) {
if r.willBeCache() == false {
has, e := r.db.Session().sn.Get(r.bean)
if e != nil {
return e
}
r.has = has
return
}
fds := r.getFields()
if len(fds) == 0 {
return errors.New("查询条件没有绑定,无法进行GET查询")
}
cKey := r.cacheKey()
//选取第一个fd
fd := fds[0]
//如果有id键,优先使用id
for _, s := range fds {
if string([]rune(s)[:3]) == "id:" {
fd = s
break
}
}
return r.getFromMemory(cKey, fd)
}
func (r *cacheRedis) getFromMemory(cKey, fd string) error {
r.has = true
var (
memKey = memoryKey(cKey, fd)
bData []byte
err error
)
data, has := r.db.mem.Get(memKey)
if has {
bData = data.([]byte)
} else {
bData, err = r.getFromRedis(cKey, fd)
if err != nil {
return err
}
r.db.mem.Set(memKey, bData, time.Minute*60*2)
}
if string(bData) == "null" {
r.has = false
}
//r.value.Elem().Set(reflect.New(r.value.Elem().Type()).Elem())
return json.Unmarshal(bData, r.bean)
}
func (r *cacheRedis) getFromRedis(cKey, fd string) (byteData []byte, err error) {
var hGetCmd *redis.StringCmd
err = r.db.redisForCacheFunc(func(p redis.Pipeliner) {
hGetCmd = p.HGet(cKey, fd)
})
if err == nil {
byteData = []byte(hGetCmd.Val())
return
}
if err != redis.Nil {
return
}
//redis.Nil
whereStr := r.parseStrForWhereParam(fd)
r.has, err = r.db.Session().sn.NoAutoCondition().Where(whereStr).Get(r.bean)
if err != nil {
return
}
var store interface{}
if r.has == false {
store = nil
} else {
store = r.bean
}
bts, err := json.Marshal(store)
if err != nil {
return
}
err = r.db.redisForCacheFunc(func(p redis.Pipeliner) {
p.HSet(cKey, fd, string(bts))
})
if err != nil {
return
}
byteData = bts
return
}
//parseStrForWhereParam ...解析字符串为查询条件
func (r *cacheRedis) parseStrForWhereParam(in string) (out string) {
l1 := strings.Split(in, ",")
var l2 []string
for _, s := range l1 {
mp := strings.Split(s, ":")
k := mp[0]
v := mp[1]
//判断v是否是一个数字类型,否则添加'v'
_, err := strconv.ParseInt(v, 10, 64)
if err != nil {
//解析数字失败,尝试解析浮点型数字
_, err = strconv.ParseFloat(v, 64)
if err != nil {
v = fmt.Sprintf("'%s'", v)
}
}
l2 = append(l2, fmt.Sprintf("%s=%s", k, v))
}
out = strings.Join(l2, " AND ")
return
}
//searchPKUKField ...
//查询主键/Unique字段,可能包含多个主键
//将主键的值保存
//字段名=>值
func (r *cacheRedis) searchPKUKField(pkVal *Map, val *reflect.Value) {
t := *val
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
panic("Check type error not Struct")
}
pkS := []string{"pk", "unique"}
//查询主键
for i := 0; i < t.NumField(); i++ {
typeF := t.Type().Field(i)
fv := t.Field(i)
if fv.Kind() == reflect.Ptr {
if fv.IsNil() {
continue
}
fv = fv.Elem()
}
if (fv.IsValid() && !fv.IsZero()) == false {
continue
}
//fmt.Printf("name:%s,Anonymous:%v\n", typeF.Name, typeF.Anonymous)
if typeF.Anonymous && fv.Kind() == reflect.Struct {
r.searchPKUKField(pkVal, &fv)
}
tagVal, ok := typeF.Tag.Lookup("xorm")
if !ok {
continue
}
if tagVal == "-" {
continue
}
tagV1 := strings.ToLower(tagVal)
for _, pv1 := range pkS {
if strings.Contains(tagV1, pv1) {
mp := *pkVal
mp[fieldName(typeF.Name)] = fv.Interface()
}
}
}
}
func (r *cacheRedis) getFields() []string {
fields := make(map[string]bool)
//扫描主键,唯一键
pkMap := make(Map)
r.searchPKUKField(&pkMap, r.value)
if len(pkMap) == 0 {
return []string{}
}
for k, v := range pkMap {
fields[fmt.Sprintf("%s:%s", k, com.ToStr(v))] = true
}
//扫描复合索引
for _, cmi := range r.cmiList {
k1 := cmi.cacheField()
if len(k1) > 0 {
fields[cmi.cacheField()] = true
}
}
return gtools.MapT.MapKeys(fields)
}
//cacheKey ...
func (r *cacheRedis) cacheKey() string {
return fmt.Sprintf("/h/%s", tableName(r.bean))
}
func (r *cacheRedis) willBeCache() (yes bool) {
v := reflect.ValueOf(r.bean)
if v.Kind() != reflect.Ptr {
panic("need a pointer for bind cache")
}
r.value = &v
cmi, ok := r.bean.(InterfaceCompoundIndexes)
if !ok {
return
}
if !cmi.UseCache() {
return
}
yes = true
r.cmiList = cmi.CompoundIndexes()
if len(r.cmiList) == 0 {
return
}
for _, cmi := range r.cmiList {
cmi.validAction(r.bean)
}
return
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。