|
|
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
|
|
|
}
|