Redis原理

Redis实用场景

为了方便开发,我打算实现一个Redis 工具集

Redis的n种妙用,不仅仅是缓存

Redis只能做缓存?太out了!

Redis 几种数据类型及应用场景

redis实现存取json格式对象/集合数据

多线程实现项目初始化完成大规模数据写入redis缓存

16个Redis常见使用场景总结

Redis 实战篇:巧用数据类型实现亿级数据统计

使用Redis的有序集合实现排行榜功能

点赞模块设计 - Redis缓存 + 定时写入数据库实现高性能点赞功能

缓存与数据库一致性

分布式缓存与DB秒级一致的灵活设计实践

集群配置

redis 集群配置实现

Redis 数据类型:

字符串类型 String

1.存储
set key value time

2.查询:
get key

3.删除:
del key

4.递增或递减:
递增语法:incr key
递增语法(指定步长):incrby key step
递减语法:decr key
递减语法(指定步长):decrby key step

5.追加内容

set ideal hello
OK
append ideal ,ideal-20 # 追加内容
(integer) 14
get ideal
"hello,ideal-20"

6.截取部分字符串:

> get ideal
"hello,ideal-20"
> getrange ideal 0 3
"hell"
> getrange ideal 0 -1
"hello,ideal-20"

(7) 替换部分字符串

语法:setrange key start

> get ideal
"hello,ideal-20"
> setrange ideal 6 bwh # 从下标为6的位置开始替换
(integer) 14
> get ideal
"hello,bwhal-20"

(8) 获取值的长度

语法:strlen key

> strlen addr1
(integer) 7

(9) 不存在的时候才设置

语法:setnx key value

不存在,则创建
存在,则失败

> setnx address guangdong # address键 不存在,则创建
(integer) 1
> get address
"guangdong"
> setnx address beijing # address键 存在,则失败
(integer) 0
> get address
"guangdong"

(10) 同时存储获取多个值

同时存储多个值:mset key1 value1 key2 value2 …
同时获取多个值:mget key1 key2
同时存储多个值(保证不存在):msetnx key1 value1 key2 value2 …

此操作为原子性操作,要失败全部失败

> mset addr1 beijing addr2 guangdong addr3 shanghai # 同时存储多个值
OK
> keys *
1) "addr3"
2) "addr2"
3) "addr1"

> mget addr1 addr2 addr3 # 同时获取多个值
1) "beijing"
2) "guangdong"
3) "shanghai"

> msetnx age1 20 age2 25 age3 30 # 第一次同时存储多个值(保证不存在)
(integer) 1
> msetnx age4 35 age5 40 age1 45 # 第二次同时存储多个值(保证不存在),失败了
(integer) 0
> 

(11) 设置对象

语法:key value (key 例如:user:1 ,value为一个json字符串)

> set user:1 {name:zhangsan,age:20} # 存一个对象
OK
> keys *
1) "user:1"
> get user:1
"{name:zhangsan,age:20}"

以上这种 user:1 的设计在 Redis 中是允许的,例子如下
语法:对象名:{id}:{filed}

> mset user:1:name lisi user:1:age 25
OK
> mget user:1:name user:1:age
1) "lisi"
2) "25"

(12) 先 get 后 set
语法:getset
先取到原来的值,然后再把新值覆盖,如果原先没有值返回 nil

> getset addr beijing # 原先没有值,返回 nil
(nil)
> get addr
"beijing"
> getset addr guangdong # 原先有值,返回原先的值,然后覆盖新值
"beijing"
> get addr
"guangdong"

列表类型 - list

(1) 添加
A:从左或从右添加元素

lpush key value:将元素添加到列表左边
Rpush key value:将元素添加到列表右边

> lpush list1 A
(integer) 1
> lpush list1 B
(integer) 2
> lpush list1 C
(integer) 3
> lrange list1 0 -1
1) "C"
2) "B"
3) "A"

B:插入新值到某个值前后

语法:linsert list before/after value newvalue

> lrange list1 0 -1
1) "A"
2) "B"
3) "C"

> linsert list1 before C XXX # 在 C 前插入 XXX
(integer) 4

> lrange list1 0 -1
1) "A"
2) "B"
3) "XXX"
4) "C"

(2) 获取:
A:根据区间获取值

语法:lrange key start end

> lrange list1 0 -1 # 获取所有值
1) "C"
2) "B"
3) "A"
 
> lrange list1 0 1 # 获取指定区间的值
1) "C"
2) "B"

B:根据下标获取值

语法:lindex list 下标

> lrange list1 0 -1
1) "C"
2) "B
> lindex list1 0
"C"
> lindex list1 1
"B"

C:获取列表的长度

语法 llen list

> llen list1
(integer) 1

(3) 删除
A:移除最左或最右的元素

lpop key:删除列表最左边的元素,且返回元素
rpop key:删除列表最右边的元素,且返回元素

> lrange list1 0 -1
1) "D"
2) "C"
3) "B"
4) "A"

> lpop list1 # 删除列表最左边的元素,且返回元素
"D"
> rpop list1 # 删除列表最右边的元素,且返回元素
"A"

> lrange list1 0 -1
1) "C"
2) "B"

B:移除指定的值

语法:lrem list num value

> lrange list1 0 -1
1) "C"
2) "C"
3) "B"
4) "A"

> lrem list1 1 A # 删除1个A
(integer) 1
> lrange list1 0 -1
1) "C"
2) "C"
3) "B"

> lrem list1 2 C # 删除2个C
(integer) 2
> lrange list1 0 -1
1) "B"
> 

C:移除最后一个元素且添加到另一个list

rpoplpush list1 list2

> lrange list1 0 -1
1) "A"
2) "B"
3) "C"

> rpoplpush list1 list2 # 移除 list1 中最后一个元素,且添加到list2 中去
"C"

> lrange list1 0 -1
1) "A"
2) "B"
> lrange list2 0 -1
1) "C"

(4) 根据下标范围截取 list

语法:ltrim list start end

> rpush list1 A
(integer) 1
> rpush list1 B
(integer) 2
> rpush list1 C
(integer) 3
> rpush list1 D
(integer) 4

> ltrim list1 1 2 # 截取下标为1到2的值
OK

> lrange list1 0 -1
1) "B"
2) "C"

(5) 替换指定下标的值
语法:lset list 下标 value

> exists list1 # 判断是否存在此list
(integer) 0
> lset list1 0 beijing # 不存在,替换报错
(error) ERR no such key

> lpush list1 guangdong # 创建一个list
(integer) 1
> lindex list1 0
"guangdong"

> lset list1 0 beijing # 存在,替换成功
OK
> lindex list1 0
"beijing"

集合类型 - set

set:一种无序(不保证有序)集合,且元素不能重复
(1) 添加

语法:sadd key value

> sadd set1 A
(integer) 1
> sadd set1 B
(integer) 1
> sadd set1 C
(integer) 1
> sadd set1 C # set的值不能重复
(integer) 0
> smembers set1 # 查询指定set的所有值,乱序
1) "B"
2) "A"
3) "C"

(2) 获取
A:获取set集合中的所有元素

语法:smembers key

> smesmbers set1 # 查询指定set的所有值,乱序
1) "B"
2) "A"
3) "C"

B:获取元素的个数

语法:scard set

> scard set1
(integer) 3

C:随机获取元素

语法:sembers set [num]

默认获取一个随机元素,后跟数字,代表随机获取几个元素

> smembers set1
1) "D"
2) "B"
3) "A"
4) "C"

> srandmember set1 # 获取一个随机元素
"D"
> srandmember set1 # 获取一个随机元素
"B"

> srandmember set1 2 # 获取两个随机元素
1) "A"
2) "D"

(3) 删除
A:删除set集合中某元素

语法:srem key value

> srem set1 C # 删除 C 这个元素
(integer) 1

> smembers set1
1) "B"
2) "A"

B:随机删除一个元素

语法:spop set

> smembers set1
1) "D"
2) "B"
3) "A"
4) "C"
> spop set1 # 随机删除一个元素
"A"
> spop set1 # 随机删除一个元素
"B"
> smembers set1
1) "D"
2) "C"

(4) 移动指定值到另一个set

语法:smove set1 set2 value

> smembers set1
1) "D"
2) "C"

> smove set1 set2 D # 从 set1 移动 D 到 set2
(integer) 1

> smembers set1
1) "C" 
> smembers set2
1) "D"

(5) 交集 并集 差集

sinter set1 set2:交集
sunion set1 set2:并集
sdiff set1 set2:差集

> sadd set1 A
(integer) 1
> sadd set1 B
(integer) 1
> sadd set1 C
(integer) 1

> sadd set2 B
(integer) 1
> sadd set2 C
(integer) 1
> sadd set2 D
(integer) 1
> sadd set2 E
(integer) 1

> sinter set1 set2 # 交集
1) "B"
2) "C"
> sunion set1 set2 # 并集
1) "D"
2) "E"
3) "C"
4) "B"
5) "A"
> sdiff set1 set2 # 差集
1) "A"

有序集合类型 - sortedset/zset

此类型和 set 一样也是 string 类型元素的集合,且不允许重复的元素
不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序
有序集合的成员是唯一,但分数(score)却可以重复
(1) 添加

语法:zadd key score value [score value … …]

> zadd sortedset1 20 zhangsan # 添加一个
(integer) 1
> zadd sortedset1 10 lisi 60 wangwu # 添加多个
(integer) 2

(2) 获取
A:获取所有值(默认排序)

语法:zrange sortedset start end [withscores]

根据那个值的大小进行了排序,例如上面的 10 20 60

> zrange sortedset1 0 -1
1) "lisi"
2) "zhangsan"
3) "wangwu"

B:获取所有值(从小到大和从大到小)

zrangebyscore sortedset -inf +inf:从小到大
zrevrange sortedset 0 -1:从大到小

> zrangebyscore sortedset1 -inf +inf # 从小到大
1) "lisi"
2) "zhangsan"
3) "wangwu"

> zrevrange sortedset1 0 -1 # 从大到小
1) "wangwu"
2) "zhangsan"
3) "lisi"

C:获取值且附带数值

zrangebyscore sortedset -inf +inf withscores:从小到大且附带值

> zrangebyscore sortedset1 -inf +inf withscores # 显示从小到大且附带值
1) "lisi"
2) "10"
3) "zhangsan"
4) "20"
5) "wangwu"
6) "60"

> zrangebyscore sortedset1 -inf 20 withscores # 显示从小到大,且数值小于20的
1) "lisi"
2) "10"
3) "zhangsan"
4) "20"
> 

D:获取有序集合中的个数

语法:zcard sortedset

> zcard sortedset1
(integer) 2

E:获取指定区间成员数量

语法:zcount sortedset start end (strat 和 end是指那个数值,而不是什么下标)

> zcount sortedset1 10 60
(integer) 3

(2) 删除

zrem key value

> zrange sortedset1 0 -1
1) "lisi"
2) "zhangsan"
3) "wangwu"

> zrem sortedset1 wangwu # 删除 wangwu 这个元素
(integer) 1

> zrange sortedset1 0 -1
1) "lisi"
2) "zhangsan"

哈希类型 - hash

(1) 添加
A:普通添加

语法:hset hash field value

> hset hash1 username admin
(integer) 1
> hset hash1 password admin
(integer) 1

B:不存在才可以添加

语法:hsetnx hash filed value

> hsetnx hash1 username admin888 # 已存在,失败
(integer) 0

> hsetnx hash1 code 666 # 不存在,成功
(integer) 1

(2) 获取
A:获取指定的field对应的值

语法:hget hash field [ key field … …]

> hget hash1 password
"admin"

B:获取所有的field和value

语法:hgetall hash

> hgetall hash1
1) "username"
2) "admin"
3) "password"
4) "admin"

C:获取 hash 的字段数量

语法:hlen hash

> hlen hash1
(integer) 2

D:只获取所有 field 或 value

hkeys hash:获取所有 field 字段
hvals hash:获取所有 value 值

> hkeys hash1 # 获取所有 field 字段
1) "username"
2) "password"

> hvals hash1 # 获取所有 value 值
1) "admin"
2) "admin"

(3) 删除

语法:hdel hash field

> hdel hash1 username
(integer) 1

(4) 自增自减

hincrby hash field 增量

> hsetnx hash1 code 666
(integer) 1
> hincrby hash1 code 2
(integer) 668
> hincrby hash1 code -68
(integer) 600

三种特殊数据类型

Geospatial(地理位置)

使用经纬度,作为地理坐标,然后存储到一个有序集合 zset/sortedset 中去保存,所以 zset 中的命令也是可以使用的

特别是需要删除一个位置时,没有GEODEL命令,是因为你可以用ZREM来删除一个元素(其结构就是一个有序结构)
Geospatial 这个类型可以用来实现存储城市坐标,一般都不是自己录入,因为城市数据都是固定的,所以都是通过 Java 直接导入的,下面都是一些例子而已
Geospatial 还可以用来实现附近的人这种概念,每一个位置就是人当前的经纬度,还有一些能够测量距离等等的方法,后面都会提到

命令列表:
(1) 存储经纬度

语法:geoadd key longitud latitude member […]

longitud——经度、 latitude——纬度

有效的经度从-180度到180度。

有效的纬度从-85.05112878度到85.05112878度。

> geoadd china:city 116.413384 39.910925 beijing
(integer) 1
> geoadd china:city 113.271431 23.135336 guangzhou
(integer) 1
> geoadd china:city 113.582555 22.276565 zhuhai
(integer) 1
> geoadd china:city 112.556391 37.876989 taiyuan
(integer) 1

(2) 获取集合中一个或者多个成员的坐标

语法:geopos key member [member…]

> geopos china:city beijing zhuhai
1) 1) "116.41338318586349487"
   2) "39.9109247398676743"
2) 1) "116.41338318586349487"
   2) "39.9109247398676743"

(3) 返回两个给定位置之间的距离

语法:geodist key member1 member2 [unit]

单位默认为米,可以修改,跟在 member 后即可,例如 km
指定单位的参数 unit 必须是以下单位的其中一个:
m 表示单位为米
km 表示单位为千米
mi 表示单位为英里
ft 表示单位为英尺

> geodist china:city guangzhou taiyuan
"1641074.3783"
> geodist china:city guangzhou taiyuan km
"1641.0744"

(4) 查找附近的元素(给定经纬度和长度)
含义:以给定的经纬度为中心, 返回集合包含的位置元素当中

语法:georadius key longitude latitude radius m|km|mi|ft [WITHCOORD][WITHDIST] [WITHHASH] [COUNT count]

与中心的距离不超过给定最大距离的所有位置元素
通过georadius就可以完成 附近的人功能(例如这个位置我们输入的是人当前的位置)
withcoord:带上坐标
withdist:带上距离,单位与半径单位相同
count :只显示前n个(按距离递增排序)

> georadius china:city 113.582555 22.276565 500 km
1) "zhuhai"
2) "guangzhou"
> georadius china:city 113.582555 22.276565 500 km withdist withcoord count 1
1) 1) "zhuhai"
   2) "0.0002"
   3) 1) "113.58255296945571899"
      2) "22.27656546780746538"
      
> georadius china:city 113.582555 22.276565 500 km withdist withcoord count 2
1) 1) "zhuhai"
   2) "0.0002"
   3) 1) "113.58255296945571899"
      2) "22.27656546780746538"
2) 1) "guangzhou"
   2) "100.7111"
   3) 1) "113.27143281698226929"
      2) "23.13533660075498233"

(5) 查找附近的元素(指定已有成员和长度)

含义:5 与 4 相同,给定的不是经纬度而是集合中的已有成员

语法:GEORADIUSBYMEMBER key member radius…

> georadiusbymember china:city zhuhai 500 km
1) "zhuhai"
2) "guangzhou"

(6) 返回一个或多个位置元素的Geohash表示

语法:geohash key member1 [member2…]

> geohash china:city zhuhai
1) "weby8xk63k0"

Hyperloglog(基数统计)

HyperLogLog 是用来做**基数(数据集中不重复的元素的个数)**统计的算法,其底层使用string数据类型
HyperLogLog 的优点是:

在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的

花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数

因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素
一个常见的例子:

传统实现,存储用户的id,然后每次进行比较。当用户变多之后这种方式及其浪费空间,而我们的目的只是计数,Hyperloglog就能帮助我们利用最小的空间完成。

(1) 添加
含义:添加指定元素到 HyperLogLog 中
语法:PFADD key element1 [elememt2…]

> pfadd test1 A B C D E F G
(integer) 1
> pfadd test2 C C C D E F G
(integer) 1

(2) 估算myelx的基数
含义:返回给定 HyperLogLog 的基数估算值
语法:PFCOUNT key [key]

> pfcount test1
(integer) 7
> pfcount test2
(integer) 5

(3) 合并
含义:将多个 HyperLogLog 合并为一个 HyperLogLog
语法:PFMERGE destkey sourcekey [sourcekey…]

> pfmerge test test1 test2
OK
> pfcount test
(integer) 9

BitMaps(位图)

BitMaps 使用位存储,信息状态只有 0 和 1

Bitma p是一串连续的2进制数字(0或1),每一位所在的位置为偏移(offset),在bitmap上可执行AND,OR,XOR,NOT以及其它位操作
这种类型的应用场景很多,例如统计员工是否打卡,或者登陆未登录,活跃不活跃,都可以考虑使用此类型

(1) 设置值

含义:为指定key的offset位设置值
语法:setbit key offset value

> setbit sign 0 1
(integer) 0
> setbit sign 1 0
(integer) 0
> setbit sign 2 0
(integer) 0
> setbit sign 3 0
(integer) 0
> setbit sign 4 1
(integer) 0
> setbit sign 5 1
(integer) 0
> setbit sign 6 1
(integer) 0

(2) 获取

含义:获取offset位的值
语法:getbit key offset

> getbit sign 4
(integer) 1
> getbit sign 2
(integer) 0

(3) 统计

含义:统计字符串被设置为1的bit数,也可以指定统计范围按字节
语法:bitcount key [start end]

> bitcount sign
(integer) 4
批量删除

scan 0 match keys* count 10000
DEL 123456

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐