深入了解 Redis(二)Redis 数据类型及操作

1、Redis 数据类型

Redis 单线程快的原因

高性能服务器不一定是多线程的
多线程 CPU 会上下文切换,比较耗时。
CPU - 内存 - 硬盘 的速度比较慢。
核心:Redis 将所有数据放在内存中,单线程操作效率很高,内存系统,没有上下问切换效率就是最高的。
redis官网地址
redis 命令参考

Redis-key

  • Redis 的 redisObject 结构
typedef struct redisObject {
	unsigned type:4; 		// 类型
	unsigned encoding:4; 	// 编码
	unsigned lru:LRU_BITS;
	int refcount;
	void *ptr;				// 指向底层实现数据结构的指针
} robj;

encoding 记录了队形使用的编码,即对象底层使用的数据结构,我们存入 key-value 键值对并不会指定对象的 encoding,Redis 会根据不同场景设置不同的编码

编码常量编码对应底层数据结构OBJECT_ENCODING 命令输出
REDIS_ENCODING_INTlong 类型整数int
REDIS_ENCODING_EMBSTRembstr 编码的简单动态字符串embstr
REDIS_ENCODING_RAW简单动态字符串raw
REDIS_ENCODING_HT字典hashtable
REDIS_ENCODING_LINKEDLIST双端链表linkedlist
REDIS_ENCODING_ZIPLIST压缩列表ziplist
REDIS_ENCODING_INTSET整数集合intset
REDIS_ENCODING_SKIPLIST跳跃表和字典skiplist

1.1 String(字符串)

数据结构:

struct sdshdr{
	int len;
	int free;
	char buf[];
}

常用命令:

127.0.0.1:6379> set key v1 # 设置值
OK
127.0.0.1:6379> get key # 获得值
"v1"
127.0.0.1:6379> keys * # 所有的 key
"key"
127.0.0.1:6379> exists key # 判断某个 key 是否存在
(integer) 1
127.0.0.1:6379> append key va2 # 追加字符串,如果不存在,相当于 setkey
(integer) 5
127.0.0.1:6379> get key
"v1va2"
127.0.0.1:6379> append key "key1"
(integer) 9
127.0.0.1:6379> get key
"v1va2key1"
127.0.0.1:6379> strlen key # 获取字符串长度
(integer) 9
127.0.0.1:6379> append key ,,,
(integer) 12
127.0.0.1:6379> get key
"v1va2key1,,,"
127.0.0.1:6379> strlen key
(integer) 12
127.0.0.1:6379> append name zhangsan
(integer) 8
127.0.0.1:6379> get name
"zhangsan"
###########################################
#		i ++
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> type views
string
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views # 增加 1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views # 减少 1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> incrby views 10 # 增加 10
(integer) 11
127.0.0.1:6379> get views
"11"
127.0.0.1:6379> decrby views 5 # 减少 5
(integer) 6
127.0.0.1:6379> get views
"6"
###########################################
#			字符串范围
127.0.0.1:6379> keys *
1) "key"
127.0.0.1:6379> set key "hello,word" # 设置字符串
OK
127.0.0.1:6379> get key
"hello,word"
127.0.0.1:6379> getrange key 0 3 # 截取字符串 [0,3]
"hell"
127.0.0.1:6379> getrange key 0 -1 # 截取全部字符串,相当于 get key
"hello,word"
#			替换字符串
127.0.0.1:6379> set key1 abdfsa
OK
127.0.0.1:6379> get key1
"abdfsa"
127.0.0.1:6379> setrange key1 1 sss # 替换指定位置开始字符串
(integer) 6
127.0.0.1:6379> getrange key1 0 -1
"assssa"
###########################################
# setex (set with expire)	# 设置过期时间
# setnx (set if not exist)	# 不存在再设置 (在分布式锁中使用)
127.0.0.1:6379> setex key2 30 "hello" # 设置 key2 的值为 hello 30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setex key2 30 "hello"
OK
127.0.0.1:6379> ttl key2
(integer) 25
127.0.0.1:6379> setnx mykey "redis" # 如果 mykey 不存在,创建 mykey
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
3) "key"
4) "mykey"
127.0.0.1:6379> ttl key2
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "key"
3) "mykey"
127.0.0.1:6379> setnx mykey "MongoDB" # 如果 mykey 存在,创建失败!
(integer) 0
127.0.0.1:6379> get mykey
"redis"
###########################################
# mset
# mget
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"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个 原子性操作!
(integer) 0
127.0.0.1:6379> get k4
(nil)

# 对象
set user:1 {name:zhangsan,age:3} # 设置一个 user:1 对象,值为 json 字符来保存一个对象

# 这里的 key 为 user:{id}:{name}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

###########################################

# getset # 先 get 再 set

127.0.0.1:6379> getset db redis # 如果不存在,返回 nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db MongoDB # 如果存在值,获取原来的值,设置新的值。
"redis"
127.0.0.1:6379> get db
"MongoDB"

应用场景:

普通的 key/value 存储。
统计多单位的数量
粉丝数
分布式锁
计数器
分布式 session
对象缓存

1.2 List ( 列表 )

list 可以作为栈,队列,阻塞队列!
list 命令已 l 开头
常用命令:

###########################################
127.0.0.1:6379> lpush list one # 头插法,将一个或多个值插入列表头部
(integer) 1
127.0.0.1:6379> lpush list tow
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取 list 中的值
1) "three"
2) "tow"
3) "one"
127.0.0.1:6379> rpush list four # 尾插法,将一个或多个值插入到列表尾部
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "one"
4) "four"
###########################################
# lpop
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "one"
4) "four"
127.0.0.1:6379> lpop list # 移除列表第一个元素
"three"
127.0.0.1:6379> rpop list # 移除列表最后一个元素
"four"
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
###########################################
# lindex
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
127.0.0.1:6379> lindex list 0 # 通过下标获取 list 中的值.
"tow"
127.0.0.1:6379> lindex list 1
"one"
###########################################
# llen
127.0.0.1:6379> llen list # 返回列表长度
(integer) 2
###########################################
# 移除指定的值 # lrem
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
127.0.0.1:6379> lrem list 1 one # 移除 list 集合中指定个数的 value,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "tow"
127.0.0.1:6379> lpush list tow
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "tow"
127.0.0.1:6379> lrem list 2 three
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "tow"
###########################################
# trim list 截取
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpush mylist "hello4"
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello4"
127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定位置元素
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
###########################################
# rpoplpush # 移除列表尾部元素并添加到新列表中
127.0.0.1:6379> rpush mylist "hel1o"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush mylist otherlist # 移除列表尾部元素并添加到新列表中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1 # 原来列表
1) "hel1o"
2) "hello1"
127.0.0.1:6379> lrange otherlist 0 -1 # 目标列表
1) "hello2"
###########################################
# 列表中指定下标的值替换为另外的值,更新操作
127.0.0.1:6379> exists list # 判断列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item # 不存在就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item # 如果存在更新下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 item2 # 不存在就会报错
(error) ERR index out of range
###########################################
# linsert # 将某个具体的具体的 value 值插入列表中
127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list word
(integer) 2
127.0.0.1:6379> linsert list before word other # 插入到指定值之前
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "word"
127.0.0.1:6379> linsert list after word new
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "word"
4) "new"
  • list 是一个链表,before,after,left,right 都可以插入值
  • 如果 key 不存在,创建新的链表
  • 如果 key 存在,新增内容
  • 如果移除了所有值,空链表,不存在
  • 在两边插入或者改动值,效率最高。

应用场景:

消息队列 Stack = LPUSH + LPOP
栈 Queue = LPUSH + RPOP
Blocking MQ = LPUSH + BRPOP
消息流

1.3 hash ( 哈希 )

Map 集合,key - map 集合,本质和 string 类型没有太大区别,是简单的 key - value
常用命令:

###########################################
127.0.0.1:6379> hset hash 1 2	# set 一个具体的 key - value
(integer) 1
127.0.0.1:6379> hset hash key1 value1
(integer) 1
127.0.0.1:6379> hget hash key1	# 获取 指定 key 的值
"value1"
127.0.0.1:6379> hmset hash key value key2 value2	# set 多个 key - value
OK
127.0.0.1:6379> hmget  hash key 1 key2	# get 多个字段值
1) "value"
2) "2"
3) "value2"
127.0.0.1:6379> hgetall hash	# 获取所有 key - value 数据
1) "1"
2) "2"
3) "key1"
4) "value1"
5) "key"
6) "value"
7) "key2"
8) "value2"
###########################################
127.0.0.1:6379> hdel hash 1	# 删除指定 key 的 value
(integer) 1
127.0.0.1:6379> hgetall hash
1) "key1"
2) "value1"
3) "key"
4) "value"
5) "key2"
6) "value2"
###########################################
127.0.0.1:6379> hlen hash	# 获取 hash 表的字段数量
(integer) 3
127.0.0.1:6379> hmset hash hello word
OK
127.0.0.1:6379> hgetall hash
1) "key1"
2) "value1"
3) "key"
4) "value"
5) "key2"
6) "value2"
7) "hello"
8) "word"
###########################################
127.0.0.1:6379> HEXISTS hash key1	# 判断 hash 中的指定字段是否存在
(integer) 1
127.0.0.1:6379> hexists hash key3
(integer) 0
###########################################
127.0.0.1:6379> hkeys hash	# 只获得所有的 key
1) "key1"
2) "key"
3) "key2"
4) "hello"
127.0.0.1:6379> hvals hash	# 只获得所有的 value
1) "value1"
2) "value"
3) "value2"
4) "word"
###########################################
127.0.0.1:6379> hset hash star 5
(integer) 1
127.0.0.1:6379> hget hash star
"5"
127.0.0.1:6379> HINCRBY hash star 1	# 指定增量 1
(integer) 6
127.0.0.1:6379> HINCRBY hash star -1
(integer) 5
127.0.0.1:6379> hsetnx hash value3 hello	# 如果不存在可以设置
(integer) 1
127.0.0.1:6379> hsetnx hash value3 word	# 存在则不能设置
(integer) 0

应用场景:

变更数据,用户信息保存,经常变动的信息,适合对象存储
购物车

1.4 set ( 集合 )

set 中的值不能重复
常用命令:

###########################################
127.0.0.1:6379> sadd set hello # set 集合中添加元素
(integer) 1
127.0.0.1:6379> sadd set hello1
(integer) 1
127.0.0.1:6379> sadd set hello2
(integer) 1
127.0.0.1:6379> SMEMBERS set	# 查看指定 set 的所有值
1) "hello2"
2) "hello1"
3) "hello"
127.0.0.1:6379> SISMEMBER set hello # 查看某个值是否在 set 集合中,存在为 1,不存在为 0
(integer) 1
127.0.0.1:6379> SISMEMBER set word
(integer) 0
###########################################
127.0.0.1:6379> scard set	# 获取 set 集合中的元素个数
(integer) 3
127.0.0.1:6379> sadd set hello
(integer) 0
127.0.0.1:6379> sadd set hello3
(integer) 1
127.0.0.1:6379> scard set
(integer) 4
###########################################
127.0.0.1:6379> srem set hello	# 移除某个元素
(integer) 1
127.0.0.1:6379> scard set
(integer) 3
127.0.0.1:6379> SMEMBERS set
1) "hello2"
2) "hello1"
3) "hello3"
###########################################
127.0.0.1:6379> SRANDMEMBER set	# 随机抽取一个元素
"hello1"
127.0.0.1:6379> SRANDMEMBER set
"hello3"
127.0.0.1:6379> SRANDMEMBER set
"hello2"
127.0.0.1:6379> SRANDMEMBER set
"hello3"
127.0.0.1:6379> srandmember set 2	# 随机抽取指定个数元素
1) "hello1"
2) "hello2"
###########################################
# 删除指定的 key,删除随机的 key
127.0.0.1:6379> spop set	# 随机删除一些 set 集合中的元素
"hello3"
127.0.0.1:6379> spop set
"hello2"
127.0.0.1:6379> SMEMBERS set
1) "hello1"
127.0.0.1:6379> SMEMBERS set
1) "hello1"
###########################################
# 一个指定的值,移动到另外一个集合中。
127.0.0.1:6379> sadd set hello
(integer) 1
127.0.0.1:6379> sadd set hello1
(integer) 1
127.0.0.1:6379> sadd set hello2
(integer) 1
127.0.0.1:6379> sadd set hello3
(integer) 1
127.0.0.1:6379> sadd set2 hello
(integer) 1
127.0.0.1:6379> smove set set2 hello1	# # 一个指定的值,移动到另外一个集合中。
(integer) 1
127.0.0.1:6379> SMEMBERS set2
1) "hello1"
2) "hello"
###########################################
# 交集,差集,并集
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2	# 查看差集
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2	# 交集 共同好友
1) "c"
127.0.0.1:6379> SUNION key1 key2	# 并集
1) "c"
2) "a"
3) "b"
4) "e"
5) "d"

应用场景:

共同好友,共同关注,推荐好友等。
商品筛选
抽奖
好友去重

1.5 zset ( 有序集合 )

set 的基础上增加了排序
常用命令:

###########################################
127.0.0.1:6379> zadd set 1 one	# 添加一个值
(integer) 1
127.0.0.1:6379> zadd set 2 two
(integer) 1
127.0.0.1:6379> zadd set 3 three 4 four	# 添加多个值
(integer) 2
127.0.0.1:6379> zrange set 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
###########################################
# 排序实现
127.0.0.1:6379> zadd sala 2500 xiaoming	# 添加三个用户
(integer) 1
127.0.0.1:6379> zadd sala 3000 zhangsan
(integer) 1
127.0.0.1:6379> zadd sala 1500 xiaohong
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE sala -inf +inf	# 最小值到最大值排序
1) "xiaohong"
2) "xiaoming"
3) "zhangsan"
127.0.0.1:6379> ZREVRANGE sala 0 -1	# 最大值到最小值排序
1) "zhangsan"
2) "xiaoming"
127.0.0.1:6379> ZRANGEBYSCORE sala -inf +inf withscores	# 最小值到最大值排序并附带成绩
1) "xiaohong"
2) "1500"
3) "xiaoming"
4) "2500"
5) "zhangsan"
6) "3000"
127.0.0.1:6379> ZRANGEBYSCORE sala -inf 2500 withscores	# 工资小于 2500 升排列
1) "xiaohong"
2) "1500"
3) "xiaoming"
4) "2500"
###########################################
127.0.0.1:6379> zrange sala 0 -1
1) "xiaohong"
2) "xiaoming"
3) "zhangsan"
127.0.0.1:6379> zrem sala xiaohong	# 移除元素
(integer) 1
127.0.0.1:6379> zrange sala 0 -1
1) "xiaoming"
2) "zhangsan"
###########################################
127.0.0.1:6379> zcard sala	# 获取有序集合中的个数
(integer) 2
###########################################
127.0.0.1:6379> ZREVRANGE sala 0 -1
1) "zhangsan"
2) "xiaoming"
127.0.0.1:6379> zadd sala 1 hello 2 word
(integer) 2
127.0.0.1:6379> zcount  sala 1 2	# 获取指定区间的元素数量
(integer) 2
127.0.0.1:6379> zrange sala 0 -1
1) "hello"
2) "word"
3) "xiaoming"
4) "zhangsan"

应用场景:

排行榜
按权重进行判断

1.6 geospatial ( 地理位置 )

附近的人,定位,经纬度查询,距离计算等

1.7 hyperloglog ( 基数统计 )

A(1,3,5,7,8,7)B(1,3,5,7,8)
基数是去掉重复元素后集合内的元素数量 = 5
优点:占用内存固定,12 KB

127.0.0.1:6379> pfadd key1 a b c d e f	# 创建第一组元素
(integer) 1
127.0.0.1:6379> pfadd key2 g h l m n a	# 创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount key1	# 查看元素数量
(integer) 6
127.0.0.1:6379> pfcount key2
(integer) 6
127.0.0.1:6379> PFMERGE key3 key1 key2	# 合并两组并集到 key3
OK
127.0.0.1:6379> pfcount key3
(integer) 11

使用场景

网页的 UV,一个人访问一个网站多次,但算作一个人,有一定错误率,有容错可以使用

1.8 bitmaps ( 位图场景 )

位存储,数据结构,操作二进制进行记录

127.0.0.1:6379> setbit sign 0 0	# 赋值
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> getbit sign 3	# 获取 指定 key 的值
(integer) 0
127.0.0.1:6379> getbit sign 4
(integer) 1
127.0.0.1:6379> bitcount sign	# 计算累加值
(integer) 1

使用场景

统计用户信息
打卡

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一起来搬砖呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值