package DaoCache import ( "dsSso/Const/ErrorConst" "dsSso/Model" "dsSso/Utils/CommonUtil" "dsSso/Utils/DbUtil" "dsSso/Utils/LogUtil" "dsSso/Utils/RedisUtil" "fmt" "github.com/go-redis/redis/v7" "reflect" "strconv" "time" ) var db = DbUtil.Engine /** 功能:优先从缓存读取,检查到缺失的,就从数据库读取,然后两个结果集拼接后返回,同时将缺失的缓存补全 作者:黄海 时间:2020-02-05 */ func GetListByIds(ids []string, m Model.Selector) []map[string]interface{} { //1、第一步从缓存读取 list, notExistsIds := batchReadRedis(ids, m.RedisPrefix) //2、如果有一些ID在缓存中不存在,那么需要从数据库中查询,然后填充到缓存中 if notExistsIds != nil && len(notExistsIds) > 0 { //从数据库中获取缺失的数据 lostCacheList := fromDb(notExistsIds, m) //缓存写入 batchWriteRedis(lostCacheList, m) //合并两个结果集 for i := 0; i < len(lostCacheList); i++ { list = append(list, lostCacheList[i]) } } return list } /*===================以下为内部函数,用于扩展从REDIS缓存中查询===========================*/ func fromDb(ids []string, m Model.Selector) []map[string]interface{} { tableName := m.TableName pkField := m.PkField //查询数据库 var idsStr = "" for i := 0; i < len(ids); i++ { idsStr = idsStr + "," + ids[i] } if len(idsStr) > 0 { idsStr = idsStr[1:] } results, err := db.SQL(`select * from `+tableName+` where find_in_set(`+pkField+`,?)`, idsStr).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, "从数据库中读取数据失败:"+err.Error()) } return results } /** 功能:批量写入缓存 作者:黄海 时间:2020-02-05 */ func batchWriteRedis(list []map[string]interface{}, m Model.Selector) { pkField := m.PkField prefix := m.RedisPrefix //声明管道 pipe := RedisUtil.RedisClient.Pipeline() for i := 0; i < len(list); i++ { bean := list[i] var pkSuffix = "" switch bean[pkField].(type) { case string: pkSuffix = bean[pkField].(string) case int64: pkSuffix = strconv.FormatInt(reflect.ValueOf(bean[pkField]).Int(), 10) } key := prefix + pkSuffix pipe.HSet(key, bean) pipe.Expire(key, 24*time.Hour) } //执行管道 pipe.Exec() } /** 功能:从REDIS中批量获取指定ID的列表信息 作者:黄海 时间:2020-02-05 */ func batchReadRedis(ids []string, prefix string) ([]map[string]interface{}, []string) { //1、创建管道 var list []*redis.StringStringMapCmd pipe := RedisUtil.RedisClient.Pipeline() for i := 0; i < len(ids); i++ { list = append(list, pipe.HGetAll(prefix+ids[i])) } //2、执行管道 _, err := pipe.Exec() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) } //存在于缓存中的数据 var existList []map[string]interface{} //3、输出结果 //不存在的主键有哪些 var notExistsIds []string for i := 0; i < len(list); i++ { _bean := list[i].Val() if len(_bean) > 0 { //将values转成Interface{},其实这个锅 Golang是不背的,因为redis中hset写入的整数,取出来hget也是字符串~ n := CommonUtil.ConvertMapStringToMapInterface(_bean) //找到了加到返回值列表中去 existList = append(existList, n) } else { notExistsIds = append(notExistsIds, ids[i]) } } //返回值 return existList, notExistsIds } /** 功能:将指定的SQL语句计算分页的SQL 作者:黄海 时间:2020-03-25 */ func PageData(baseSql string, model Model.Selector, args ...interface{}) ([]map[string]interface{}, int32) { //条件查询语句 conditionSql := fmt.Sprintf("%s %s %s", " order by ", model.PkField, " limit ? offset ? ") //分页的语句 pageSql := fmt.Sprintf("%s %s", baseSql, conditionSql) //分页数据 list, err := db.SQL(pageSql, args...).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) } //总数 list2, err := db.SQL(baseSql, args...).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) } //有哪些ids? var ids = CommonUtil.Ids(list, model.PkField) //-->缓存层-->数据库-->缓存 list = GetListByIds(ids, model) return list, int32(len(list2)) }