Redis
Redis简单介绍
Redis(Remote Dictionary Server,即远程字典服务)是一个开源的、使用ANSI C语言编写的 Key-Value 数据库。它通常被用作内存数据结构服务器,因为它具有高速读写、原子性操作、丰富的数据结构以及可持久化存储等特点。
Redis是一种键值型的NoSql数据库,这里有两个关键字:
- 键值型
- NoSql
其中键值型,是指Redis中存储的数据都是以key.value对的形式存储,而value的形式多种多样,可以是字符串.数值.甚至json:
而NoSql则是相对于传统关系型数据库而言,有很大差异的一种数据库。
对于存储的数据,没有类似Mysql那么严格的约束,比如唯一性,是否可以为null等等,所以我们把这种松散结构的数据库,称之为NoSQL数据库。
Redis的基本工作原理
- 数据存储:Redis将数据存储在内存中,这使得读写操作非常快速。为了实现这一功能,Redis使用了一种叫做内存映射(memory-mapped)的技术,将数据存储在内存中并定期将数据写入磁盘以实现持久化。
- 数据备份:Redis支持两种主要的数据备份方法:RDB(Redis DataBase)和AOF(Append Only File)。RDB是Redis基于当前自身的所有数据所生成的数据快照,纯粹的数据,若redis从rdb启动,可直接加载使用。AOF文件类似Redis日志文件,记录的是Redis接受到的写命令,若redis从aof启动,需要先读aof文件,然后执行里面的命令,生产数据。
- 性能优化:为了保证效率,Redis使用了一些优化策略。例如,它使用IO多路复用来处理多个客户端的请求,避免单线程模型下的性能瓶颈。此外,Redis还支持数据类型的原子操作,例如对字符串的增加和减少、集合的增加和删除元素等操作都是原子性的。
- 高可用性和可扩展性:Redis支持主从复制,可以实现高可用性和可扩展性。通过主从复制,当一个Redis实例发生故障时,其他实例可以接管其职责,保证服务的可用性。
Redis常见命令
Redis数据结构介绍
Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样:
Redis为了方便我们学习,将操作不同数据类型的命令也做了分组,在官网( redis.io/commands )可以查看到不同的命令
Redis 通用命令
通用指令是部分数据类型的,都可以使用的指令,常见的有:
- KEYS:查看符合模板的所有key
- DEL:删除一个指定的key
- EXISTS:判断key是否存在
- EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
- TTL:查看一个KEY的剩余有效期
通过help [command] 可以查看一个命令的具体用法,例如:
- DEL
127.0.0.1:6379> help del
DEL key [key ...]
summary: Delete a key
since: 1.0.0
group: generic
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3 #批量添加数据
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
4) "age"
127.0.0.1:6379> del k1 k2 k3 k4
(integer) 3 #此处返回的是成功删除的key,由于redis中只有k1,k2,k3 所以只成功删除3个,最终返回
127.0.0.1:6379>
127.0.0.1:6379> keys * #再查询全部的key
1) "age" #只剩下一个了
127.0.0.1:6379>
- EXPIRE
内存非常宝贵,对于一些数据,我们应当给他一些过期时间,当过期时间到了之后,他就会自动被删除~
127.0.0.1:6379> expire age 10
(integer) 1
127.0.0.1:6379> ttl age
(integer) 8
127.0.0.1:6379> ttl age
(integer) 6
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> ttl age
(integer) -2 #当这个key过期了,那么此时查询出来就是-2
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set age 10 #如果没有设置过期时间
OK
127.0.0.1:6379> ttl age
(integer) -1 # ttl的返回值就是-1
Redis命令-String命令
String类型,也就是字符串类型,是Redis中最简单的存储类型。
其value是字符串,不过根据字符串的格式不同,又可以分为3类:
- string:普通字符串
- int:整数类型,可以做自增.自减操作
- float:浮点类型,可以做自增.自减操作
String的常见命令有:
- SET:添加或者修改已经存在的一个String类型的键值对
- GET:根据key获取String类型的value
- MSET:批量添加多个String类型的键值对
- MGET:根据多个key获取多个String类型的value
- INCR:让一个整型的key自增1
- INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2
- INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
- SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
- SETEX:添加一个String类型的键值对,并且指定有效期
- SET 和GET: 如果key不存在则是新增,如果存在则是修改
127.0.0.1:6379> set name Rose //原来不存在
OK
127.0.0.1:6379> get name
"Rose"
127.0.0.1:6379> set name Jack //原来存在,就是修改
OK
127.0.0.1:6379> get name
"Jack"
- MSET和MGET
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> MGET name age k1 k2 k3
1) "Jack" //之前存在的name
2) "10" //之前存在的age
3) "v1"
4) "v2"
5) "v3"
- INCR和INCRBY和DECY
127.0.0.1:6379> get age
"10"
127.0.0.1:6379> incr age //增加1
(integer) 11
127.0.0.1:6379> get age //获得age
"11"
127.0.0.1:6379> incrby age 2 //一次增加2
(integer) 13 //返回目前的age的值
127.0.0.1:6379> incrby age 2
(integer) 15
127.0.0.1:6379> incrby age -1 //也可以增加负数,相当于减
(integer) 14
127.0.0.1:6379> incrby age -2 //一次减少2个
(integer) 12
127.0.0.1:6379> DECR age //相当于 incr 负数,减少正常用法
(integer) 11
127.0.0.1:6379> get age
"11"
- SETNX
127.0.0.1:6379> help setnx
SETNX key value
summary: Set the value of a key, only if the key does not exist
since: 1.0.0
group: string
127.0.0.1:6379> set name Jack //设置名称
OK
127.0.0.1:6379> setnx name lisi //如果key不存在,则添加成功
(integer) 0
127.0.0.1:6379> get name //由于name已经存在,所以lisi的操作失败
"Jack"
127.0.0.1:6379> setnx name2 lisi //name2 不存在,所以操作成功
(integer) 1
127.0.0.1:6379> get name2
"lisi"
- SETEX
127.0.0.1:6379> setex name 10 jack
OK
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) 7
127.0.0.1:6379> ttl name
(integer) 5
Redis应用案例
Go语言连接Redis
使用 go get -u 命令从 GitHub 获取并更新已安装的软件包
go get -u github.com/go-redis/redis/v8
Go连接Redis简单案例
package main
import (
"fmt"
"gopkg.org/gomodule.v3/redis/v8"
)
func main() {
client := redis.NewClient(&redis.Options{
Network: "tcp",
Address: "localhost:6379",
Password: "", // no password set
})
// 检查连接
err := client.Ping().Err()
if err != nil {
fmt.Println("无法连接到 Redis:", err)
return
}
// 设置一个键值
err = client.Set("key", "value", 0).Err()
if err != nil {
fmt.Println("无法设置 Redis 键值:", err)
return
}
// 获取键值
value, err := client.Get("key").Result()
if err != nil {
fmt.Println("无法获取 Redis 键值:", err)
return
}
fmt.Println("从 Redis 获取的值:", value)
// 关闭连接
err = client.Close()
if err != nil {
fmt.Println("关闭 Redis 连接失败:", err)
return
}
}
连续签到
要实现每日连续签到功能,你需要使用Redis的键空间通知功能来监听指定键空间的变化。当某个键的值为指定的签到时间戳时,触发签到逻辑。
以下是一个使用Go语言连接Redis并实现每日连续签到功能的示例代码:
package main
import (
"fmt"
"time"
"gopkg.in/redis.v5"
)
func main() {
// 创建Redis客户端
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // 如果没有设置密码,将Password设为空字符串
})
// 检查连接
err := client.Ping().Err()
if err != nil {
fmt.Println("无法连接到 Redis:", err)
return
}
// 设置签到时间间隔(以秒为单位)
checkInterval := 24 * 60 * 60 // 一天
// 获取当前用户ID(这里假设用户ID为1)
userID := 1
// 获取当前时间
currentTime := time.Now()
// 计算下一次签到时间
nextCheckTime := calculateNextCheckTime(currentTime, checkInterval)
fmt.Printf("下一次签到时间: %s\n", nextCheckTime.Format("2006-01-02 15:04:05"))
// 将下一次签到时间存储到Redis中,以备之后比较
err = client.Set(fmt.Sprintf("check_time_%d", userID), nextCheckTime.Unix(), 0).Err()
if err != nil {
fmt.Println("无法设置签到时间:", err)
return
}
// 监听指定键空间的变化
keySpaceChannel := make(chan string)
go func() {
for {
message := <-keySpaceChannel
fmt.Println("Key Space Notification:", message)
// 在这里执行签到逻辑,判断message是否为签到时间戳,如果是则记录签到信息
}
}()
client.KeySpaceNotifyAdd(fmt.Sprintf("check_time_%d", userID), keySpaceChannel)
// 关闭Redis连接
err = client.Close()
if err != nil {
fmt.Println("关闭 Redis 连接失败:", err)
return
}
}
// 计算下一次签到时间
func calculateNextCheckTime(currentTime time.Time, checkInterval int) time.Time {
// 获取当前时间的下一个完整天(与上一天的0点对齐)
nextDay := currentTime.AddDate(0, 0, 1).Truncate(24 * time.Hour)
// 计算下一个签到时间的秒数间隔
checkTimeUnix := int64(nextDay.Unix()) + int64(checkInterval)
// 将秒数间隔转换为时间格式
nextCheckTime := time.Unix(checkTimeUnix, 0)
return nextCheckTime
}
在上述代码中,我们首先创建了一个Redis客户端,并连接到Redis服务器。然后,我们计算出下一次签到时间,并将该时间存储到Redis中。接下来,我们使用KeySpaceNotifyAdd方法监听指定键空间的变化,当指定的键值发生变化时,会通过keySpaceChannel通道接收通知。在接收到通知后,我们执行签到逻辑,判断接收到的消息是否为签到时间戳,如果是则记录签到信息。最后,我们关闭Redis连接。