package CacheUtil import ( "dsSupport/Utils/CommonUtil" "dsSupport/Utils/DbUtil" "dsSupport/Utils/ErrorConst" "dsSupport/Utils/LogUtil" "dsSupport/Utils/RedisUtil" "fmt" "github.com/go-redis/redis/v7" "reflect" "strconv" "strings" "time" ) /** 功能:优先从缓存读取,检查到缺失的,就从数据库读取,然后两个结果集拼接后返回,同时将缺失的缓存补全 作者:黄海 时间:2020-02-05 */ func GetListByIds(ids []string, m 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) //change by zhangjun 2020-05-19 //合并两个结果集 list2, _ := batchReadRedis(notExistsIds, m.RedisPrefix) for i := 0; i < len(list2); i++ { list = append(list, list2[i]) } } return list } /** 功能:删除指定ID的缓存 作者:黄海 时间:2020-02-21 */ func DeleteCacheByIds(ids []string, m Selector) { prefix := m.RedisPrefix for i := 0; i < len(ids); i++ { id := ids[i] key := prefix + id RedisUtil.DEL(key) } } /*===================以下为内部函数,用于扩展从REDIS缓存中查询===========================*/ func fromDb(idAry []string, m Selector) []map[string]interface{} { tableName := m.TableName pkField := m.PkField //查询数据库 ids := strings.Join(idAry, "','") sqlRaw := fmt.Sprintf(`select * from `+tableName+` where `+pkField+` in ('%s')`, ids) results, err := DbUtil.Engine.SQL(sqlRaw).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, "从数据库中读取数据失败:"+err.Error()) } return results } /** 功能:批量写入缓存 作者:黄海 时间:2020-02-05 */ func batchWriteRedis(list []map[string]interface{}, m 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) } //执行管道 //change by zhangjun 2020-05-15 //pipe.Exec() _, err := pipe.Exec() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) } } /** 功能:从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语句和获取查询总数的SQL语句 作者:黄海 时间:2020-02-21 */ func count(baseSql string, pkField string, args []interface{}) (int32, error) { //替换掉分页代码,获取数据量总数 countSql := strings.Replace(baseSql, "SELECT "+pkField+" ", "SELECT count(*) as count ", -1) var count int32 //去掉最后的limit+offset args = args[0 : len(args)-2] _, err := DbUtil.Engine.SQL(countSql, args...).Get(&count) if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return 0, err } return count, nil } /** 功能:将指定的SQL语句计算分页的SQL 作者:黄海 时间:2020-03-25 */ func Page(baseSql string, args ...interface{}) ([]map[string]interface{}, int32, error) { var model Selector //删除多余的空格 baseSql = CommonUtil.DeleteExtraSpace(baseSql) arr := strings.Split(baseSql, " ") for i := 0; i < len(arr)-1; i++ { if strings.ToLower(arr[i]) == "from" { model = GetBean(arr[i+1]) break } } //条件查询语句 conditionSql := fmt.Sprintf("%s", " limit ? offset ? ") //分页的语句 pageSql := fmt.Sprintf("%s %s", baseSql, conditionSql) //分页数据 list, err := DbUtil.Engine.SQL(pageSql, args...).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } //总数 count, err := count(baseSql, model.PkField, args) if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } //有哪些ids? var ids = CommonUtil.Ids(list, model.PkField) //-->缓存层-->数据库-->缓存 list = GetListByIds(ids, model) return list, count, nil }