这是我参与【第五届青训营】伴学笔记创作活动的第十三天。redis 作为数据缓冲中起重要作用的工具,在企业应用中起重要作用。今天就写一下 go redis 的基础知识。
Go Redis 基础
go redis 安装配置
- 下载地址:Redis
- 安装 go-redis :go get github.com/go-redis/redis/v9
redis 用法
redis 连接及基本使用
import "github.com/ go-redis/redis/v9"
var rdb *redis.Client
func init() {
// redis 客户端的基本配置
rdb = redis. NewClient(&redis.options{
Addr :" localhost:6379"
Password: "", // no password set
DB: 0, // use default DB
})
}
func main() {
ctx := context.Background()
// 法一
// key + value + 过期时间 (0 为永久保存)
err := rdb.Set(ctx, "gokey", "govalue", 0).Err() // 相当于一个 map 设置值
if err != nil {
panic(err)
}
val, err := rdb.Get(ctx, "gokey").Result() // 获得 key 为 gokey 的值
// 法二: 自定义用法
result, err := rdb.Do(ctx, "get", "gokey", "govalue").Result() // 获取值为interface{} 类型
if err != nil {
panic(err)
}
val := result.(valuetype)
}
Redis 基本类型及使用
可以看看文档 Redis五种基本数据类型_redis的五种数据类型_NeverOW的博客-CSDN博客
String 类型
-
Set,Get 命令
-
GetSet 命令
// 返回 gokey 旧值并设定新值为 new value oldval, err := rdb.GetSet(ctx, "gokey", "new value").Result() -
SetNX 命令
// 不存在则设置值 err := rdb.SetNX(ctx, "key1", "value1", 0).Err() -
MGet 命令
// 批量查询 data, err := rdb.MGet(ctx, "key1", "key2", "key3").Result() for val := range data { } -
Mset 命令
// 批量设置值 // 可用 map err := rdb.MSet(ctx, "key1", "value1", "key2", "value2").Err() -
Incr, IncrBy, Decr, DecrBy 命令
// 针对一个 key 的数值进行递增的操作 val, err := rdb.Incr(ctx, "key").Result() val, err := rdb.IncrBy(ctx, "key", 2).Result() // IncrByFloat 可以设定 float 值 // 相应的 Decr 类型为递减,且用法和 Incr 一致 -
Del 命令
err := rdb.Del(ctx, "key1", "key2").Err() // 删除 -
Expire 命令
// 设置过期时间 rdb.Expire(ctx, "key", 10 * time.Second)
Hash 类型
-
HSet 命令
// hash表 id + 字段名 + 字段值 err := rdb.HSet(ctx, "user_1", "username", "zhangsan") -
HGet 命令
username, err := rdb.HGet(ctx, "user_1", "username") -
HMSet, HMGet ,HSetNX, HIncr 等同 String 一样
-
HKeys 命令
keys, err := rdb.Hkeys(ctx, "user_1").Result() // 返回所有字段名 -
HExists 命令
exist, err := rdb.HExists(ctx, "user_1", "username").Result() // 判断是否存在
List 类型
-
LPush,RPush 命令
rdb.LPush(ctx, "key", 1, 2, 3, 4) // 从列表左边插入数据 -
RPop, LPop 命令
val, err := rdb.RPop(ctx, "key").Result() //从列表右边删除一个数据,并返回该数据 -
LRange 命令
vals, err := rdb.LRange(ctx, "key", 0, 1) // 取下标为 [0,1] 的数据 -
LRem, LIndex,LInsert 等用法可以看看参考文档
Set 类型
参考 c++ 的 set 类型
Sorted Set 类型
存储自动排序的 set 类型数据
err := rdb.ZAdd(ctx, "key", &redis.Z{Score: 3.7, Member: "zhangsan"}).Err // 根据分数从小到大排序
vals, err := rdb.ZRange(ctx, "key", 0, -1).Result()
if err != nil {
panic(err)
}
for _, val := range vals {
fmt.Println(val)
}
Redis 两个重要功能
发布订阅
Redis提供了发布订阅功能,可以用于消息的传输。Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。
-
Subscribe 函数
ctx := context.Background() sub := rdb.Subscribe(ctx, "channel1") // 订阅 // 接收消息:法一 for ch := range sub.Channel() { fmt.Println(ch.Channel) // 频道名称 fmt.Println(ch.PayLoad) // 收到的内容 } // 法二 for { message, err := sub.RecieveMessage(ctx) if err != nil { panic(err) } fmt.Println(ch.Channel) // 频道名称 fmt.Println(ch.PayLoad) // 收到的内容 } -
Publish 函数
ctx := context.Background() rdb.Publish(ctx, "channel1", "msg") // 发步消息 -
PSubscribe 函数
// 支持格式订阅 sub := rdb.PSubscribe(ctx, "channel_*") -
Unsubscribe 函数: 取消订阅
-
PubSubNumSub 函数
ctx := context.Background() chs, _ := rdb.PubSubNumSub(ctx, "channel_1").Result() for ch, count := range chs { fmt.Println(ch) // channel 名字 fmt.Println(count) // 订阅者数量 }
事务处理
redis事务可以一次执行多个命令,并且带有以下两个重要的性质:
- 事务是一个单独的隔离操作:务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
TxPipeline
pipe := rdb.TxPipeline() // 开启一个事务
// 执行事务操作, 可以通过 pipe 读写 redis
ctx := context.Background()
chs, _ := rdb.PubSubNumSub(ctx, "channel_1").Result()
_, err := pipe.Exec(ctx) // 提交事务
fmt.Println(chs.Val(), err) // 可以查询事务操作过程中的结果
watch
// redis 乐观锁支持,通过 watch 监听一些 Key
ctx := context.Background()
// 定义一个回调函数,用于处理事务逻辑
fn := func(tx *redis.Tx) error{
// 先查询一下当前 watch 监听的 key 的值
v, err := tx.Get(ctx, "key").Int()
if err != nil && err != redis.Nil {
return err
}
// 开始处理业务
v++
// 结束处理业务
// 如果 key 的值没有变化, Pipelined 函数才能执行成功
_, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
// 这里给 key 设置新值
pipe.Set(ctx, "key", v, 0)
return nil
})
}
for i := 0; i < 3; i++ {
err := rdb.Watch(ctx, fn, "key1", "key2")
if err == nil {
break
}
if err == redis.TxFailedErr {
continue
}
}