跳转到帖子
  • 游客您好,欢迎来到黑客世界论坛!您可以在这里进行注册。

    赤队小组-代号1949(原CHT攻防小组)在这个瞬息万变的网络时代,我们保持初心,创造最好的社区来共同交流网络技术。您可以在论坛获取黑客攻防技巧与知识,您也可以加入我们的Telegram交流群 共同实时探讨交流。论坛禁止各种广告,请注册用户查看我们的使用与隐私策略,谢谢您的配合。小组成员可以获取论坛隐藏内容!

    TheHackerWorld官方

  • 0

Go操作Redis实战


HACK1949

问题

Go操作Redis实战

5fe8689677e99.png

目录

  • 安装Redis客户端
    • 连接redis
  • 基本指令
    • Keys():根据正则获取keys
    • Type():获取key对应值得类型
    • Del():删除缓存项
    • Exists():检测缓存项是否存在
    • Expire(),ExpireAt():设置有效期
    • TTL(),PTTL():获取有效期
    • DBSize():查看当前数据库key的数量
    • FlushDB():清空当前数据
    • FlushAll():清空所有数据库
  • 字符串(string)类型
    • Set():设置
    • SetEX():设置并指定过期时间
    • SetNX():设置并指定过期时间
    • Get():获取
    • GetRange():字符串截取
    • Incr():增加+1
    • IncrBy():按指定步长增加
    • Decr():减少-1
    • DecrBy():按指定步长减少
    • Append():追加
    • StrLen():获取长度
  • 列表(list)类型
    • LPush():将元素压入链表
    • LInsert():在某个位置插入新元素
    • LSet():设置某个元素的值
    • LLen():获取链表元素个数
    • LIndex():获取链表下标对应的元素
    • LRange():获取某个选定范围的元素集
    • 从链表左侧弹出数据
    • LRem():根据值移除元素
  • 集合(set)类型
    • SAdd():添加元素
    • SPop():随机获取一个元素
    • SRem():删除集合里指定的值
    • SSMembers():获取所有成员
    • SIsMember():判断元素是否在集合中
    • SCard():获取集合元素个数
    • SUnion():并集,SDiff():差集,SInter():交集
  • 有序集合(zset)类型
    • ZAdd():添加元素
    • ZIncrBy():增加元素分值
    • ZRange()、ZRevRange():获取根据score排序后的数据段
    • ZRangeByScore()、ZRevRangeByScore():获取score过滤后排序的数据段
    • ZCard():获取元素个数
    • ZCount():获取区间内元素个数
    • ZScore():获取元素的score
    • ZRank()、ZRevRank():获取某个元素在集合中的排名
    • ZRem():删除元素
    • ZRemRangeByRank():根据排名来删除
    • ZRemRangeByScore():根据分值区间来删除
  • 哈希(hash)类型
    • HSet():设置
    • HMset():批量设置
    • HGet():获取某个元素
    • HGetAll():获取全部元素
    • HDel():删除某个元素
    • HExists():判断元素是否存在
    • HLen():获取长度

安装Redis客户端

Go语言中使用第三方库https://github.com/go-redis/redis连接Redis数据库并进行操作。使用以下命令下载并安装:

go get github.com/go-redis/redis/v8

注:导入时指定了版本v8,忽略版本是一个常见错误

连接redis

说明:Background返回一个非空的Context。 它永远不会被取消,没有值,也没有期限。 它通常在main函数,初始化和测试时使用,并用作传入请求的顶级上下文。

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

//Background返回一个非空的Context。 它永远不会被取消,没有值,也没有期限。 
//它通常在main函数,初始化和测试时使用,并用作传入请求的顶级上下文。
var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	pong, err := rdb.Ping(ctx).Result()
	if err != nil {
		fmt.Printf("连接redis出错,错误信息:%v", err)
	}
    fmt.Println("成功连接redis")
}

基本指令

Keys():根据正则获取keys

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	//*表示获取所有的key
	keys, err := rdb.Keys(ctx, "*").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(keys)
}

Type():获取key对应值得类型

Type()方法用户获取一个key对应值的类型

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	vType, err := rdb.Type(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(vType) //string
}

Del():删除缓存项

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	n, err := rdb.Del(ctx, "key1", "key2").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("成功删除了 %v 个\n", n)
}

Exists():检测缓存项是否存在

Exists()方法用于检测某个key是否存在

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	n, err := rdb.Exists(ctx, "key1").Result()
	if err != nil {
		panic(err)
	}
	if n > 0 {
		fmt.Println("存在")
	} else {
		fmt.Println("不存在")
	}
}

注:Exists()方法可以传入多个key,返回的第一个结果表示存在的key的数量,不过工作中我们一般不同时判断多个key是否存在,一般就判断一个key,所以判断是否大于0即可,如果判断判断传入的多个key是否都存在,则返回的结果的值要和传入的key的数量相等

Expire(),ExpireAt():设置有效期

需要在设置好了缓存项后,在设置有效期

Expire()方法是设置某个时间段(time.Duration)后过期,ExpireAt()方法是在某个时间点(time.Time)过期失效

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	res, err := rdb.Expire(ctx, "key", time.Minute * 2).Result()
	if err != nil {
		panic(err)
	}
	if res {
		fmt.Println("设置成功")
	} else {
		fmt.Println("设置失败")
	}
	
	res, err = rdb.ExpireAt(ctx, "key2", time.Now()).Result()
	if err != nil {
		panic(err)
	}
	if res {
		fmt.Println("设置成功")
	} else {
		fmt.Println("设置失败")
	}
}

TTL(),PTTL():获取有效期

TTL()方法可以获取某个键的剩余有效期

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	//设置一分钟的有效期
	rdb.Expire(ctx, "key", time.Minute)

	//获取剩余有效期,单位:秒(s)
	ttl, err := rdb.TTL(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(ttl)

	//获取剩余有效期,单位:毫秒(ms)
	pttl, err := rdb.PTTL(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(pttl)
}

DBSize():查看当前数据库key的数量

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	num, err := rdb.DBSize(ctx).Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("数据库有 %v 个缓存项\n", num)
}

FlushDB():清空当前数据

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

    //清空当前数据库,因为连接的是索引为0的数据库,所以清空的就是0号数据库
	res, err := rdb.FlushDB(ctx).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(res)//OK
}

FlushAll():清空所有数据库

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	res, err := rdb.FlushAll(ctx).Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(res)//OK
}

字符串(string)类型

Set():设置

仅仅支持字符串(包含数字)操作,不支持内置数据编码功能。如果需要存储Go的非字符串类型,需要提前手动序列化,获取时再反序列化。

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	_, err := rdb.Ping(ctx).Result()
	//fmt.Println(pong, err)
	if err != nil {
		fmt.Printf("连接redis出错,错误信息:%v", err)
		return
	}
	//Set方法的最后一个参数表示过期时间,0表示永不过期
	err = rdb.Set(ctx, "key1", "value1", 0).Err()
	if err != nil {
		panic(err)
	}

	//key2将会在两分钟后过期失效
	err = rdb.Set(ctx, "key2", "value2", time.Minute * 2).Err()
	if err != nil {
		panic(err)
	}
}

SetEX():设置并指定过期时间

设置键的同时,设置过期时间

示例:

package main

import (
	"context"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	err := rdb.SetEX(ctx, "key", "value", time.Hour * 2).Err()
	if err != nil {
		panic(err)
	}
}

SetNX():设置并指定过期时间

注:SetNX()与SetEX()的区别是,SexNX()仅当key不存在的时候才设置,如果key已经存在则不做任何操作,而SetEX()方法不管该key是否已经存在缓存中直接覆盖

介绍了SetNX()SetEX()的区别后,还有一点需要注意的时候,如果我们想知道我们调用SetNX()是否设置成功了,可以接着调用Result()方法,返回的第一个值表示是否设置成功了,如果返回false,说明缓存Key已经存在,此次操作虽然没有错误,但是是没有起任何效果的。如果返回true,表示在此之前key是不存在缓存中的,操作是成功的

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})
	
	res, err := rdb.SetNX(ctx, "key", "value", time.Minute).Result()
	if err != nil {
		panic(err)
	}
	if res {
		fmt.Println("设置成功")
	} else {
		fmt.Printf("key已经存在缓存中,设置失败")
	}
}

Get():获取

如果要获取的key在缓存中并不存在,Get()方法将会返回redis.Nil

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	err := rdb.Set(ctx, "key", "value", 0).Err()
	if err != nil {
		panic(err)
	}

	val, err := rdb.Get(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key: %v\n", val)
	
	val2, err := rdb.Get(ctx, "key-not-exist").Result()
	if err == redis.Nil {
		fmt.Println("key不存在")
	} else if err != nil {
		panic(err)
	} else {
		fmt.Printf("值为: %v\n", val2)
	}
}

GetRange():字符串截取

GetRange()方法可以用来截取字符串的部分内容,第二个参数是下标索引的开始位置,第三个参数是下标索引的结束位置(不是要截取的长度)

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	err := rdb.Set(ctx, "key", "Hello World!", 0).Err()
	if err != nil {
		panic(err)
	}

	val, err := rdb.GetRange(ctx, "key", 1, 4).Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key: %v\n", val) //截取到的内容为: ello
}

注:即使key不存在,调用GetRange()也不会报错,只是返回的截取结果是空"",可以使用fmt.Printf("%q\n", val)来打印测试

Incr():增加+1

Incr()IncrBy()都是操作数字,对数字进行增加的操作,incr是执行原子加1操作,incrBy是增加指定的数

所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何context witch(切换到另一个线程).

(1)在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只能发生于指令之间。

(2)在多线程中,不能被其它进程(线程)打算的操作叫原子操作。

Redis单命令的原子性主要得益于Redis的单线程

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	val, err := rdb.Incr(ctx, "number").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key当前的值为: %v\n", val)
}

IncrBy():按指定步长增加

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	val, err := rdb.IncrBy(ctx, "number", 12).Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key当前的值为: %v\n", val)
}

Decr():减少-1

Decr()DecrBy()方法是对数字进行减的操作,和Incr正好相反

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	val, err := rdb.Decr(ctx, "number").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key当前的值为: %v\n", val)
}

DecrBy():按指定步长减少

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	val, err := rdb.DecrBy(ctx, "number", 12).Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("key当前的值为: %v\n", val)
}

Append():追加

Append()表示往字符串后面追加元素,返回值是字符串的总长度

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr:     "172.16.147.128:6379",
		Password: "",
		DB:       0,
	})

	err := rdb.Set(ctx, "key", "hello", 0).Err()
	if err != nil {
		panic(err)
	}
	length, err := rdb.Append(ctx, "key", " world!").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("当前缓存key的长度为: %v\n", length) //12
	val, err := rdb.Get(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Printf("当前缓存key的值为: %v\n", val) //hello world!
}

StrLen():获取长度

StrLen()方法可以获取字符串的长度

示例:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

链接帖子
意见的链接
分享到其他网站

这个问题有0个答案

推荐的帖子

此问题没有答案

黑客攻防讨论组

黑客攻防讨论组

    You don't have permission to chat.
    • 最近浏览   0位会员

      • 没有会员查看此页面。
    ×
    ×
    • 创建新的...