Browse Source

redis数据库迁移模块

v1
超级管理员 2 years ago
parent
commit
b5f7f3aaef
  1. 464
      api/version1/datamanagement/redisController/redis.go
  2. 622
      api/version1/datamanagement/redisController/runredis.go
  3. 96
      api/version1/datamanagement/redisController/type.go
  4. 2
      api/version1/entry.go
  5. 2
      apirouter/entry.go
  6. 23
      apirouter/v1/redisRouter/type.go
  7. 3
      initialization/route/initRoute.go

464
api/version1/datamanagement/redisController/redis.go

@ -0,0 +1,464 @@
package redisController
import (
"appPlatform/overall/publicmethod"
"context"
"fmt"
"sort"
"strconv"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
)
/*
*
@ 作者: 秦东
@ 时间: 2023-11-13 14:27:45
@ 功能: 测试数据库链接
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (a *ApiMethod) TestRedisLink(c *gin.Context) {
var redisConfig RedisConfig
err := c.ShouldBindJSON(&redisConfig)
if err != nil {
publicmethod.Result(10001, err, c)
return
}
if redisConfig.Ip == "" {
redisConfig.Ip = "127.0.0.1"
}
if redisConfig.Port == 0 {
redisConfig.Port = 6379
}
var redisDbConst RunOneRedis
redisDbConst.Ip = redisConfig.Ip
redisDbConst.Port = redisConfig.Port
redisDbConst.Pwd = redisConfig.Pwd
redisDbConst.DbName = 10
redisDb := redisDbConst.OpenRedis()
// pingLink, err := redisDb.Ping(context.Background()).Result()
_, err = redisDb.Ping(context.Background()).Result()
redisRunDb := InitRedis(redisDb)
redisCont, redisErr := redisRunDb.ConfigGet("databases")
// sendData := publicmethod.MapOut[string]()
// sendData["linkUrl"] = redisDb
// sendData["pingLink"] = pingLink
// sendData["err"] = err
// sendData["redisErr"] = redisErr
// sendData["redisCont"] = len(redisCont)
var sendInfo RedisLinkState
if err == nil {
sendInfo.IsTrue = 1
} else {
sendInfo.IsTrue = 2
publicmethod.Result(10001, sendInfo, c)
return
}
if redisErr != nil {
sendInfo.DbNumber = 16
} else {
sendInfo.DbNumber = 16
if len(redisCont) == 2 {
for k, v := range redisCont {
if k == 1 {
if val, isOk := v.(string); isOk {
sendInfo.DbNumber, _ = strconv.Atoi(val)
}
}
}
}
}
var redisListCont CountRedisKeyNumber
for i := 0; i < sendInfo.DbNumber; i++ {
syncSeting.Add(1)
go redisListCont.TallyRedisKeys(redisConfig.Ip, redisConfig.Pwd, redisConfig.Port, i)
}
syncSeting.Wait()
//根据维度序号排序
redisList := redisListCont.RedisList
sort.Slice(redisList, func(i, j int) bool {
return redisList[i].DbName < redisList[j].DbName
})
sendInfo.RedisList = redisList
// sendData["redisListCont"] = sendInfo
// sendData["redisListContlen"] = len(sendInfo)
publicmethod.Result(0, sendInfo, c)
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-14 10:19:13
@ 功能: 获取Redis有多少个数据库
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func GainRedisDbNumber(redisDb *redis.Client) (dbNumber int) {
redisRunDb := InitRedis(redisDb)
redisCont, redisErr := redisRunDb.ConfigGet("databases")
if redisErr != nil {
dbNumber = 16
} else {
dbNumber = 16
if len(redisCont) == 2 {
for k, v := range redisCont {
if k == 1 {
if val, isOk := v.(string); isOk {
dbNumber, _ = strconv.Atoi(val)
}
}
}
}
}
return
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-13 16:32:45
@ 功能: 计算Redis数据库键个数
@ 参数
#ip Redis数据库地址
#port 端口
#pwd 密码
#dbId 数据库值
@ 返回值
#
@ 方法原型
#
*/
func (c *CountRedisKeyNumber) TallyRedisKeys(ip, pwd string, port, dbId int) {
var redisDbConst RunOneRedis
redisDbConst.Ip = ip
redisDbConst.Port = port
redisDbConst.Pwd = pwd
redisDbConst.DbName = dbId
redisDb := redisDbConst.OpenRedis()
redisRunDb := InitRedis(redisDb)
val, err := redisRunDb.Keys("*")
// fmt.Printf("%v---->%v\n", dbId, val)
if err == nil {
var redisInfo RedisKeyNumber
redisInfo.DbName = dbId
redisInfo.DbNumber = len(val)
c.RedisList = append(c.RedisList, redisInfo)
}
defer syncSeting.Done()
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-13 16:11:18
@ 功能: 打开Redis
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (r *RunOneRedis) OpenRedis() (redisDb *redis.Client) {
linkUrl := fmt.Sprintf("%v:%v", r.Ip, r.Port)
redisDb = redis.NewClient(&redis.Options{
Addr: linkUrl,
Password: r.Pwd,
DB: r.DbName,
})
return
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-14 08:04:08
@ 功能: 迁移数据库
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (a *ApiMethod) MoveOldRedisToNewRedis(c *gin.Context) {
// var callBalackMsg MoveRedisMsg
var requestData MoveRedis
err := c.ShouldBindJSON(&requestData)
if err != nil {
publicmethod.Result(10001, err, c)
return
}
if requestData.OriginRedis.State != 1 || requestData.TargetRedis.State != 1 {
publicmethod.Result(10001, err, c, "请先测试源Redis与目标Redis是否链接成功!")
return
}
if requestData.OriginRedis.Ip == "" || requestData.TargetRedis.Ip == "" {
publicmethod.Result(10001, err, c, "请检查源RedisIP与目标RedisIP是否已填写!")
return
}
if requestData.OriginRedis.Port == 0 {
requestData.OriginRedis.Port = 6379
}
if requestData.TargetRedis.Port == 0 {
requestData.TargetRedis.Port = 6379
}
// //源Redis链接
var redisDbOriginConst RunOneRedis
redisDbOriginConst.Ip = requestData.OriginRedis.Ip
redisDbOriginConst.Port = requestData.OriginRedis.Port
redisDbOriginConst.Pwd = requestData.OriginRedis.Pwd
redisDbOriginConst.DbName = 0
redisDbOrigin := redisDbOriginConst.OpenRedis()
_, err = redisDbOrigin.Ping(context.Background()).Result()
if err != nil {
publicmethod.Result(10001, err, c, "源Redis链接失败!")
return
}
// //目标Redis链接
// var redisDbTargetConst RunOneRedis
// redisDbTargetConst.Ip = requestData.TargetRedis.Ip
// redisDbTargetConst.Port = requestData.TargetRedis.Port
// redisDbTargetConst.Pwd = requestData.TargetRedis.Pwd
// redisDbTargetConst.DbName = 10
// redisDbTarget := redisDbTargetConst.OpenRedis()
// _, err = redisDbTarget.Ping(context.Background()).Result()
// if err != nil {
// publicmethod.Result(10001, err, c, "目标Redis链接失败!")
// return
// }
var redisMsg NewCopyOldRedisInfo
if len(requestData.DbList) > 0 {
for _, v := range requestData.DbList {
syncSeting.Add(1)
go redisMsg.NewsMoveOldRedis(requestData.OriginRedis, requestData.TargetRedis, v)
}
} else {
dbNum := GainRedisDbNumber(redisDbOrigin)
for i := 0; i < dbNum; i++ {
syncSeting.Add(1)
go redisMsg.NewsMoveOldRedis(requestData.OriginRedis, requestData.TargetRedis, i)
}
}
syncSeting.Wait()
redisList := redisMsg.MsgList
sort.Slice(redisList, func(i, j int) bool {
return redisList[i].DbName < redisList[j].DbName
})
publicmethod.Result(0, redisList, c)
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-14 08:30:52
@ 功能: 数据迁移
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (n *NewCopyOldRedisInfo) NewsMoveOldRedis(oldRedis, newRedis RedisLink, dbName int) {
// fmt.Printf("dbName--->%v\n", dbName)
var msgCont MoveRedisMsg
msgCont.DbName = dbName
var redisDbOriginConst RunOneRedis
redisDbOriginConst.Ip = oldRedis.Ip
redisDbOriginConst.Port = oldRedis.Port
redisDbOriginConst.Pwd = oldRedis.Pwd
redisDbOriginConst.DbName = dbName
redisDbOrigin := redisDbOriginConst.OpenRedis()
_, err := redisDbOrigin.Ping(context.Background()).Result()
if err == nil {
//目标Redis链接
var redisDbTargetConst RunOneRedis
redisDbTargetConst.Ip = newRedis.Ip
redisDbTargetConst.Port = newRedis.Port
redisDbTargetConst.Pwd = newRedis.Pwd
redisDbTargetConst.DbName = dbName
redisDbTarget := redisDbTargetConst.OpenRedis()
_, err = redisDbTarget.Ping(context.Background()).Result()
if err == nil {
oldRunDb := InitRedis(redisDbOrigin)
val, err := oldRunDb.Keys("*")
if err != nil {
var keyMsg MsgListInfo
keyMsg.Keys = "源数据库"
keyMsg.State = 2
keyMsg.Msg = err
msgCont.MsgList = append(msgCont.MsgList, keyMsg)
} else {
if len(val) > 1 {
newRunDb := InitRedis(redisDbTarget)
for _, v := range val {
var keyMsg MsgListInfo
keyMsg.Keys = v
vInfo, vErr := oldRunDb.KeyType(v)
// fmt.Printf("%v: %v\n", v, vInfo)
if vErr == nil {
switch vInfo {
case "string": //字符串
_, oldVal := oldRunDb.Get(v)
oldTTl, _ := oldRunDb.TTl(v)
if oldTTl < 0 {
oldTTl = 0
}
keyMsg.State = 1
newRunDb.SetRedisTime(oldTTl)
newRunDb.Set(v, oldVal)
keyMsg.Msg = "迁移完成!"
// fmt.Printf("%v:-------------->1--->%v--->%v--->%v\n", v, oldTTl, oldTTl < 0, oldVal)
case "list": //列表
oldVal, oldErr := oldRunDb.Lrange(v, 0, -1)
if oldErr == nil {
oldTTl, _ := oldRunDb.TTl(v)
if oldTTl < 0 {
oldTTl = 0
}
newRunDb.SetRedisTime(oldTTl)
for _, ov := range oldVal {
newRunDb.Rpushx(v, ov)
}
keyMsg.Msg = "迁移完成!"
keyMsg.State = 1
} else {
keyMsg.Msg = oldErr
keyMsg.State = 2
}
// fmt.Printf("%v:-------------->2\n", v)
case "set": //集合
oldVal, isTrue := oldRunDb.Smembers(v)
if isTrue == nil {
oldTTl, _ := oldRunDb.TTl(v)
if oldTTl < 0 {
oldTTl = 0
}
newRunDb.SetRedisTime(oldTTl)
newRunDb.Sadd(v, oldVal)
keyMsg.Msg = "迁移完成!"
keyMsg.State = 1
} else {
keyMsg.Msg = "键不存在!"
keyMsg.State = 2
}
// fmt.Printf("%v:-------------->3\n", v)
case "zset": //有序集
oldVal, isTrue := oldRunDb.Zrange(v, 0, -1)
if isTrue == nil {
oldTTl, _ := oldRunDb.TTl(v)
if oldTTl < 0 {
oldTTl = 0
}
newRunDb.SetRedisTime(oldTTl)
newRunDb.Zadd(v, oldVal)
keyMsg.Msg = "迁移完成!"
keyMsg.State = 1
} else {
keyMsg.Msg = "键不存在!"
keyMsg.State = 2
}
// fmt.Printf("%v:-------------->4\n", v)
case "hash": //哈希表
oldVal, isTrue := oldRunDb.HashGetAll(v)
if isTrue {
oldTTl, _ := oldRunDb.TTl(v)
if oldTTl < 0 {
oldTTl = 0
}
newRunDb.SetRedisTime(oldTTl)
newVal := publicmethod.MapOut[string]()
for ni, nv := range oldVal {
newVal[ni] = nv
}
newRunDb.HashMsetAdd(v, newVal)
keyMsg.Msg = "迁移完成!"
keyMsg.State = 1
} else {
keyMsg.Msg = "键不存在!"
keyMsg.State = 2
}
// fmt.Printf("%v:-------------->5\n", v)
default:
keyMsg.Msg = "键不存在!"
keyMsg.State = 2
// fmt.Printf("%v:-------------->6\n", v)
}
} else {
keyMsg.Msg = vErr
keyMsg.State = 2
}
msgCont.MsgList = append(msgCont.MsgList, keyMsg)
}
} else {
var keyMsg MsgListInfo
keyMsg.Keys = "源数据库"
keyMsg.Msg = "没有要迁移的数据!"
keyMsg.State = 2
msgCont.MsgList = append(msgCont.MsgList, keyMsg)
}
}
} else {
var keyMsg MsgListInfo
keyMsg.Keys = "目标数据库"
keyMsg.Msg = err
keyMsg.State = 2
msgCont.MsgList = append(msgCont.MsgList, keyMsg)
}
} else {
var keyMsg MsgListInfo
keyMsg.Keys = "源数据库"
keyMsg.Msg = err
keyMsg.State = 2
msgCont.MsgList = append(msgCont.MsgList, keyMsg)
}
n.MsgList = append(n.MsgList, msgCont)
defer syncSeting.Done()
}

622
api/version1/datamanagement/redisController/runredis.go

@ -0,0 +1,622 @@
package redisController
import (
"appPlatform/overall"
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
type RedisStoreType struct {
Expiration time.Duration
PreKey string
Context context.Context
RedisDb *redis.Client
}
// 启动redis
func InitRedis(redisClient *redis.Client) *RedisStoreType {
var redisStoreType RedisStoreType
redisStoreType.Expiration = time.Second * 300
redisStoreType.PreKey = fmt.Sprintf("%v:", overall.CONSTANT_CONFIG.RedisPrefixStr.PreFix)
redisStoreType.Context = context.Background()
redisStoreType.RedisDb = redisClient
return &redisStoreType
}
// 设置键前缀
func (r *RedisStoreType) SetRedisPrefix(prefix string) {
r.PreKey = prefix
}
// 设置过期时间
func (r *RedisStoreType) SetRedisTime(timeDate int64) {
r.Expiration = time.Second * time.Duration(timeDate)
}
func (r *RedisStoreType) SetRedisTimes(timeDate time.Duration) {
r.Expiration = time.Second * timeDate
}
// 获取数据库配置
func (r *RedisStoreType) ConfigGet(key string) ([]interface{}, error) {
err := r.RedisDb.ConfigGet(r.Context, key)
return err.Val(), err.Err()
}
// 设置字符串
func (r *RedisStoreType) Set(key string, value string) bool {
err := r.RedisDb.Set(r.Context, key, value, r.Expiration).Err()
// fmt.Printf("设置字符串:%v\n", err)
if err != nil {
return false
}
return true
}
// 获取字符串
func (r *RedisStoreType) Get(key string) (bool, string) {
err := r.RedisDb.Get(r.Context, key)
if err.Err() != nil {
return false, ""
}
return true, err.Val()
}
/*
*Keys 命令用于查找所有符合给定模式 pattern key
*/
func (r *RedisStoreType) Keys(key string) (val []string, err error) {
val, err = r.RedisDb.Keys(r.Context, key).Result()
return
}
/*
*以秒为单位返回 key 的剩余过期时间
*/
func (r *RedisStoreType) TTl(key string) (val int64, err error) {
redisVal := r.RedisDb.TTL(r.Context, key)
err = redisVal.Err()
val = redisVal.Val().Microseconds() / 1000000
return
}
func (r *RedisStoreType) PTTl(key string) (val time.Duration, err error) {
redisVal := r.RedisDb.PTTL(r.Context, key)
err = redisVal.Err()
val = time.Duration(redisVal.Val().Microseconds())
return
}
/*
*返回数据键类型
*/
func (r *RedisStoreType) KeyType(key string) (val string, err error) {
redisObject := r.RedisDb.Type(r.Context, key)
err = redisObject.Err()
val = redisObject.Val()
return
}
// 删除键
func (r *RedisStoreType) DelKey(key string) bool {
err := r.RedisDb.Del(r.Context, key).Err()
if err != nil {
return false
}
return true
}
//哈希操作
/*
获取单个哈希键值
@hashName 集合名称
@hashKey 哈希键
callback
errs 状态
hashVal 获得值
*/
func (r *RedisStoreType) HashGet(hashName, hashKey string) (errs bool, hashVal string) {
err := r.RedisDb.HGet(r.Context, hashName, hashKey)
if err.Err() != nil {
return false, ""
}
return true, err.Val()
}
/*
为哈希表中的字段赋值 单一设置
@hashName 集合名称
@hashKey 哈希键
@hashVal 要添加的值
*/
func (r *RedisStoreType) HashSet(hashName, hashKey, hashVal string) bool {
err := r.RedisDb.HSet(r.Context, hashName, hashKey, hashVal).Err()
if err != nil {
return false
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, hashName)
} else {
r.RedisDb.PExpire(r.Context, hashName, r.Expiration)
}
// global.GVA_REDIS.PExpire(r.Context, hashName, r.Expiration)
return true
}
/*
同时将多个 field-value (字段-)对设置到哈希表中
@hashName 集合名称
@hashVal 要添加的键与值
*/
func (r *RedisStoreType) HashMsetAdd(hashName string, hashVal map[string]interface{}) bool {
// rdb := RedisInit()
err := r.RedisDb.HMSet(r.Context, hashName, hashVal).Err()
// fmt.Printf("错误sss=========》%v=====2====》%v\n", err, hashVal)
// err := rdb.HMSet(ctx, "userfg", hashVal).Err()
if err != nil {
return false
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, hashName)
} else {
r.RedisDb.PExpire(r.Context, hashName, r.Expiration)
}
return true
}
func (r *RedisStoreType) HashMsetAddinterface(hashName string, hashVal interface{}) bool {
// rdb := RedisInit()
err := r.RedisDb.HMSet(r.Context, hashName, hashVal).Err()
// fmt.Printf("错误sss=========》%v=====2====》%v\n", err, hashVal)
// err := rdb.HMSet(ctx, "userfg", hashVal).Err()
if err != nil {
return false
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, hashName)
} else {
r.RedisDb.PExpire(r.Context, hashName, r.Expiration)
}
return true
}
func (r *RedisStoreType) HashMsetAddAry(hashName string, hashVal []map[string]interface{}) bool {
// rdb := RedisInit()
err := r.RedisDb.HMSet(r.Context, hashName, hashVal).Err()
// err := rdb.HMSet(ctx, "userfg", hashVal).Err()
if err != nil {
return false
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, hashName)
} else {
r.RedisDb.PExpire(r.Context, hashName, r.Expiration)
}
// global.GVA_REDIS.PExpire(r.Context, hashName, r.Expiration)
// fmt.Printf("错误sss=========》%v\n", hashVal)
return true
}
/*
返回哈希表中所有的字段和值
@hashName 集合名称
@hashKey 哈希键
*/
func (r *RedisStoreType) HashGetAll(hashName string) (map[string]string, bool) {
// rdb := RedisInit()
// fmt.Printf("strKEy:===>%v\n", hashName)
val, err := r.RedisDb.HGetAll(r.Context, hashName).Result()
// fmt.Printf("strKEy:==1=>%v==1=>%v\n", val, err)
if err != nil {
return val, false
}
if len(val) == 0 {
return val, false
}
return val, true
}
//Redis 列表(List)
/*
*
Linsert 命令用于在列表的元素前或者后插入元素当指定元素不存在于列表中时不执行任何操作
当列表不存在时被视为空列表不执行任何操作
如果 key 不是列表类型返回一个错误
@key 列表
@op 插入状态 (1:在pivot之后2在pivot之前)
@pivot 定位值
@value 要插入值
*/
func (r *RedisStoreType) Linsert(key string, op int, pivot, value interface{}) (int64, bool) {
BeforeOrAfter := "BEFORE"
if op != 1 {
BeforeOrAfter = "AFTER"
}
linsert, linsertErr := r.RedisDb.LInsert(r.Context, key, BeforeOrAfter, pivot, value).Result()
if linsertErr != nil {
return 0, false
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return linsert, true
}
/*
*
Lindex 命令用于通过索引获取列表中的元素你也可以使用负数下标 -1 表示列表的最后一个元素 -2 表示列表的倒数第二个元素以此类推
@key 列表
@index 索引
*/
func (r *RedisStoreType) Lindex(key string, index int64) (val string, err error) {
val, err = r.RedisDb.LIndex(r.Context, key, index).Result()
return
}
/*
*
Llen 命令用于返回列表的长度 如果列表 key 不存在 key 被解释为一个空列表返回 0 如果 key 不是列表类型返回一个错误
@key 列表
*/
func (r *RedisStoreType) Llen(key string) (val int64, err error) {
val, err = r.RedisDb.LLen(r.Context, key).Result()
return
}
/*
*
Lpop 命令用于移除并返回列表的第一个元素
@key 列表
*/
func (r *RedisStoreType) Lpop(key string) (val string, err error) {
val, err = r.RedisDb.LPop(r.Context, key).Result()
return
}
/*
*
Lpush 命令将一个或多个值插入到列表头部 如果 key 不存在一个空列表会被创建并执行 LPUSH 操作 key 存在但不是列表类型时返回一个错误
@key 列表
@value 要插入的字符串
*/
func (r *RedisStoreType) Lpush(key string, value ...interface{}) (val int64, err error) {
val, err = r.RedisDb.LPush(r.Context, key, value).Result()
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return
}
/*
*
Lpushx 将一个值插入到已存在的列表头部列表不存在时操作无效
@key 列表
@value 要插入的字符串
*/
func (r *RedisStoreType) Lpushx(key, value string) (val int64, err error) {
val, err = r.RedisDb.LPushX(r.Context, key, value).Result()
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return
}
/*
*
Lrange 返回列表中指定区间内的元素区间以偏移量 START END 指定 其中 0 表示列表的第一个元素 1 表示列表的第二个元素以此类推 你也可以使用负数下标 -1 表示列表的最后一个元素 -2 表示列表的倒数第二个元素以此类推
@key 列表
@start 起始值
@stop 结束值
*/
func (r *RedisStoreType) Lrange(key string, start, stop int64) (val []string, err error) {
val, err = r.RedisDb.LRange(r.Context, key, start, stop).Result()
return
}
/*
*
Lrem 根据参数 COUNT 的值移除列表中与参数 VALUE 相等的元素
COUNT 的值可以是以下几种
count > 0 : 从表头开始向表尾搜索移除与 VALUE 相等的元素数量为 COUNT
count < 0 : 从表尾开始向表头搜索移除与 VALUE 相等的元素数量为 COUNT 的绝对值
count = 0 : 移除表中所有与 VALUE 相等的值
@start = COUNT
@key 列表
*/
func (r *RedisStoreType) Lrem(key string, start int64, value ...interface{}) (val int64, err error) {
val, err = r.RedisDb.LRem(r.Context, key, start, value).Result()
return
}
/*
*
Redis Lset 通过索引来设置元素的值
当索引参数超出范围或对一个空列表进行 LSET 返回一个错误
@key 列表
@indexes 索引值
*/
func (r *RedisStoreType) Lset(key string, indexes int64, value ...interface{}) (val string, err error) {
val, err = r.RedisDb.LSet(r.Context, key, indexes, value).Result()
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return
}
/*
*
Ltrim 对一个列表进行修剪(trim)就是说让列表只保留指定区间内的元素不在指定区间之内的元素都将被删除
下标 0 表示列表的第一个元素 1 表示列表的第二个元素以此类推 你也可以使用负数下标 -1 表示列表的最后一个元素 -2 表示列表的倒数第二个元素以此类推
@key 列表
@start 起始值
@stop 结束值
*/
func (r *RedisStoreType) Ltrim(key string, start, stop int64) (val string, err error) {
val, err = r.RedisDb.LTrim(r.Context, key, start, stop).Result()
return
}
/*
*
Rpop 命令用于移除列表的最后一个元素返回值为移除的元素
@key 列表
*/
func (r *RedisStoreType) Rpop(key string) (val string, err error) {
val, err = r.RedisDb.RPop(r.Context, key).Result()
return
}
/*
*
Rpoplpush 命令用于移除列表的最后一个元素并将该元素添加到另一个列表并返回
@sourceKey 源列表
@newKey 目标列表
*/
func (r *RedisStoreType) Rpoplpush(sourceKey, newKey string) (val string, err error) {
val, err = r.RedisDb.RPopLPush(r.Context, sourceKey, newKey).Result()
return
}
/*
*
Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)
如果列表不存在一个空列表会被创建并执行 RPUSH 操作 当列表存在但不是列表类型时返回一个错误
@key 列表
@value 要插入的字符串
*/
func (r *RedisStoreType) Rpush(key string, value ...interface{}) (val int64, err error) {
val, err = r.RedisDb.RPush(r.Context, key, value).Result()
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return
}
/*
*
Rpushx 命令用于将一个值插入到已存在的列表尾部(最右边)如果列表不存在操作无效
@key 列表
@value 要插入的字符串
*/
func (r *RedisStoreType) Rpushx(key string, value ...interface{}) (val int64, err error) {
val, err = r.RedisDb.RPushX(r.Context, key, value).Result()
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
return
}
/*
*
Blpop 命令移出并获取列表的第一个元素 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
@key 列表
*/
func (r *RedisStoreType) Blpop(key string) (val []string, err error) {
val, err = r.RedisDb.BLPop(r.Context, r.Expiration, key).Result()
return
}
/*
*
Brpop 命令移出并获取列表的最后一个元素 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
@key 列表
*/
func (r *RedisStoreType) Brpop(key string) (val []string, err error) {
val, err = r.RedisDb.BRPop(r.Context, r.Expiration, key).Result()
return
}
/*
*
Brpoplpush 命令从列表中取出最后一个元素并插入到另外一个列表的头部 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
@source 源列表
@destination 目标列表
*/
func (r *RedisStoreType) Brpoplpush(source, destination string) (val string, err error) {
val, err = r.RedisDb.BRPopLPush(r.Context, source, destination, r.Expiration).Result()
return
}
/*
Redis (key)
Redis 键命令用于管理 redis 的键
*/
/*
Redis SCAN 命令
Redis Scan 命令用于迭代数据库中的数据库键
SCAN 命令是一个基于游标的迭代器每次被调用之后 都会向用户返回一个新的游标 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数 以此来延续之前的迭代过程
SCAN 返回一个包含两个元素的数组 第一个元素是用于进行下一次迭代的新游标 而第二个元素则是一个数组 这个数组中包含了所有被迭代的元素如果新游标返回 0 表示迭代已结束
相关命令
SSCAN 命令用于迭代集合键中的元素
HSCAN 命令用于迭代哈希键中的键值对
ZSCAN 命令用于迭代有序集合中的元素包括元素成员和元素分值
*/
func (r *RedisStoreType) Scan(cursor uint64, match string, count int64) (keys []string, cursores uint64, err error) {
keys, cursores, err = r.RedisDb.Scan(r.Context, cursor, match, count).Result()
return
}
/*
集合操作
*/
/**
@ 作者: 秦东
@ 时间: 2023-11-14 09:44:32
@ 功能: Redis Smembers 命令返回集合中的所有的成员 不存在的集合 key 被视为空集合
@ 参数
#key
@ 返回值
#
@ 方法原型
#
*/
func (r *RedisStoreType) Smembers(key string) ([]string, error) {
redisClient := r.RedisDb.SMembers(r.Context, key)
return redisClient.Val(), redisClient.Err()
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-14 09:47:54
@ 功能: Redis Sadd 命令将一个或多个成员元素加入到集合中已经存在于集合的成员元素将被忽略
假如集合 key 不存在则创建一个只包含添加的元素作成员的集合
当集合 key 不是集合类型时返回一个错误
注意 Redis2.4 版本以前 SADD 只接受单个成员值
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (r *RedisStoreType) Sadd(key string, val []string) (msg []string) {
if len(val) > 0 {
for _, v := range val {
redisClient := r.RedisDb.SAdd(r.Context, key, v)
if redisClient.Err() == nil {
msg = append(msg, fmt.Sprintf("集合%v添加%v成功", key, v))
} else {
msg = append(msg, fmt.Sprintf("集合%v添加%v失败", key, v))
}
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
}
return
}
/*
*有序集合
*/
/**
@ 作者: 秦东
@ 时间: 2023-11-14 10:02:56
@ 功能: Redis Zrange 返回有序集中指定区间内的成员
其中成员的位置按分数值递增(从小到大)来排序
具有相同分数值的成员按字典序(lexicographical order )来排列
如果你需要成员按
值递减(从大到小)来排列请使用 ZREVRANGE 命令
下标参数 start stop 都以 0 为底也就是说 0 表示有序集第一个成员 1 表示有序集第二个成员以此类推
你也可以使用负数下标 -1 表示最后一个成员 -2 表示倒数第二个成员以此类推
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (r *RedisStoreType) Zrange(key string, start, stop int64) ([]string, error) {
redisClient := r.RedisDb.ZRange(r.Context, key, start, stop)
return redisClient.Val(), redisClient.Err()
}
/*
*
@ 作者: 秦东
@ 时间: 2023-11-14 10:05:51
@ 功能: Redis Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中
如果某个成员已经是有序集的成员那么更新这个成员的分数值并通过重新插入这个成员元素来保证该成员在正确的位置上
分数值可以是整数值或双精度浮点数
如果有序集合 key 不存在则创建一个空的有序集并执行 ZADD 操作
key 存在但不是有序集类型时返回一个错误
注意 Redis 2.4 版本以前 ZADD 每次只能添加一个元素
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
func (r *RedisStoreType) Zadd(key string, val []string) (msg []string) {
if len(val) > 0 {
for _, v := range val {
redisClient := r.RedisDb.ZAdd(r.Context, key, &redis.Z{1, v})
if redisClient.Err() == nil {
msg = append(msg, fmt.Sprintf("有序集合%v添加%v成功", key, v))
} else {
msg = append(msg, fmt.Sprintf("有序集合%v添加%v失败", key, v))
}
}
if r.Expiration == 0 {
r.RedisDb.Persist(r.Context, key)
} else {
r.RedisDb.PExpire(r.Context, key, r.Expiration)
}
}
return
}

96
api/version1/datamanagement/redisController/type.go

@ -0,0 +1,96 @@
package redisController
import (
"appPlatform/overall/publicmethod"
"sync"
"github.com/gin-gonic/gin"
)
/*
*
@ 作者: 秦东
@ 时间: 2023-11-13 13:56:53
@ 功能: Redis数据控制器相关操作
@ 参数
#
@ 返回值
#
@ 方法原型
#
*/
type ApiMethod struct{}
// Redis数据控制器入口
func (a *ApiMethod) Index(c *gin.Context) {
outputCont := publicmethod.MapOut[string]()
outputCont["index"] = "Redis数据控制器入口"
publicmethod.Result(0, outputCont, c)
}
// 协程设置
var syncSeting = sync.WaitGroup{}
// 链接基础配置
type RedisConfig struct {
Ip string `json:"ip"`
Port int `json:"port"`
Pwd string `json:"pwd"`
}
// 判断链接是否接通
type RedisLink struct {
RedisConfig
State int `json:"state"`
}
// 执行单一库
type RunOneRedis struct {
RedisConfig
DbName int `json:"dbName"`
}
// 数据库连通情况
type RedisLinkState struct {
IsTrue int `json:"isTrue"`
DbNumber int `json:"dbNumber"`
RedisList []RedisKeyNumber `json:"redisList"`
}
// redis数据库数据键个数
type RedisKeyNumber struct {
DbName int `json:"dbName"`
DbNumber int `json:"dbNumber"`
}
// 计算各个redis数据库数据键个数
type CountRedisKeyNumber struct {
RedisList []RedisKeyNumber `json:"redisList"`
}
// 迁移Redis
type MoveRedis struct {
OriginRedis RedisLink `json:"originRedis"` //源
TargetRedis RedisLink `json:"targetRedis"` //目标
DbList []int `json:"dblist"` //要迁移的库
}
// 迁移Redis执行信息
type MoveRedisMsg struct {
DbName int `json:"dbName"`
MsgList []MsgListInfo `json:"msgList"`
}
type MsgListInfo struct {
Keys string `json:"keys"`
State int `json:"state"`
Msg interface{} `json:"msg"`
}
type NewCopyOldRedisInfo struct {
MsgList []MoveRedisMsg `json:"msgList"`
}

2
api/version1/entry.go

@ -2,6 +2,7 @@ package version1
import (
"appPlatform/api/version1/customerform"
"appPlatform/api/version1/datamanagement/redisController"
"appPlatform/api/version1/dict"
"appPlatform/api/version1/grantpowers"
matrixapi "appPlatform/api/version1/matrixApi"
@ -24,6 +25,7 @@ type ApiEntry struct {
TaskManagementApi taskmanagement.ApiMethod
TaskFlowApi taskflow.ApiMethod
NewsClassApi newsclass.ApiMethod //新闻类
RedisManagApi redisController.ApiMethod
}
var AppApiEntry = new(ApiEntry)

2
apirouter/entry.go

@ -10,6 +10,7 @@ import (
menusrouters "appPlatform/apirouter/v1/menusRouters"
"appPlatform/apirouter/v1/newsclassrouter"
"appPlatform/apirouter/v1/public"
"appPlatform/apirouter/v1/redisRouter"
"appPlatform/apirouter/v1/taskrouter"
userrouters "appPlatform/apirouter/v1/userRouters"
)
@ -27,6 +28,7 @@ type RouterGroup struct {
CustomerFormRouter customerformrouter.ApiRouter
TaskRouter taskrouter.ApiRouter
NewsClassApiRouter newsclassrouter.ApiRouter
RedisClassApiRouter redisRouter.ApiRouter
}
var RouterGroupEntry = new(RouterGroup)

23
apirouter/v1/redisRouter/type.go

@ -0,0 +1,23 @@
package redisRouter
import (
"appPlatform/api/version1"
"github.com/gin-gonic/gin"
)
// Redis控制器路由类
type ApiRouter struct{}
// 权限管理PC端
func (a *ApiRouter) RouterGroup(router *gin.RouterGroup) {
apiRouter := router.Group("redis")
var methodBinding = version1.AppApiEntry.RedisManagApi
{
apiRouter.GET("", methodBinding.Index) //入口
apiRouter.POST("", methodBinding.Index) //入口
apiRouter.POST("testRedisLink", methodBinding.TestRedisLink) //测试数据库链接
apiRouter.POST("moveOldRedisToNewRedis", methodBinding.MoveOldRedisToNewRedis) //迁移数据库
}
}

3
initialization/route/initRoute.go

@ -70,6 +70,9 @@ func InitialRouter() *gin.Engine {
//注册新闻类接口
newsClassApiRouter := apirouter.RouterGroupEntry.NewsClassApiRouter
newsClassApiRouter.RouterGroup(VerifyIdentity)
//注册Redis数据管理接口
redisClassApiRouter := apirouter.RouterGroupEntry.RedisClassApiRouter
redisClassApiRouter.RouterGroup(VerifyIdentity)
}
//验证身份接口 无需鉴权Url(主要web端使用)
VerifyIdentityWeb := router.Group("")

Loading…
Cancel
Save