redis数据库学习一
一、redis数据库介绍
1.介绍
redis数据在内存中,读取速度快,但易丢失,是key-value型数据库,类比于字典,通过key去操作value,mysql数据在磁盘中读取速度慢。key-value一一对应,请求回应模式,使用TCP与redis数据通信,对于发送的请求redis必须做出回应。
2.1安装redis
git clone https://gitee.com/mirrors/redis.git -b 6 .2cd redismakemake testmake install# 默认安装在 /usr/local/bin# redis-server 是服务端程序# redis-cli 是客户端程序
2.2启动redis
mkdir redis-data# 把 redis 文件夹下 redis.conf 拷贝到 redis-data# 修改 redis.conf# requirepass 修改密码 123456# daemonize yescd redis-dataredis-server redis.conf# 通过 redis-cli 访问 redis-serverredis-cli -h 127 .0.0.1 -a 123456
3. 五种基本类型
4.redis简单操作
4.1 string操作
4.2 list操作
list为key,对应的value是一个双向循环list,返回value使用lrange,返回全部元素索引为(0,-1)
4.3 hash操作
4.4 set操作
set为一个集合,集合中的元素不能重复
4.5 zset操作:
zset是一个有序的集合,value格式是(c1, m1),c1是序号scores,一个m1出现新的c1会覆盖以前的。
redis的key-value结构是一个散列表,value有不同的结构
安全的二进制字符串指:在一段字符串前有字符串长度,以长度结束的字符串,不以\0结束的字符串。
具有唯一性的数据结构可以实现数据去重。
redis中value编码
redis内存数据库:
1.到底是要运行速度快,还是要存储效率高;
2.数据量少的时候,存储效率高为主;
3.数据量多的时候,运行速度快为主;
二、基本操作
1.string类型
字符数组类型, 该字符串是动态字符串raw,当字符串长度小于1M时,加倍扩容;超过1M每次之扩容1M;最大长度为512M;
注意:redis字符串是二进制安全字符串;可以存储图片,二进制协议等二进制数据;
1.1 基础命令
#
设置
key
的
value
值
SET key val
#
获取
key
的
value
GET key
#
执行原子加一的操作
INCR key
#
执行原子加一个整数的操作
INCRBY key increment
#
执行原子减一的操作
DECR key
#
执行原子减一个整数的操作
DECRBY key decrement
#
如果
key
不存在,这种情况下等同
SET
命令。 当
key
存在时,什么也不做
# set Not eXist ok
这个命令是否执行了
0,1
是不是操作结果是不是成功
SETNX key value
#
删除
key val
键值对
DEL key
#
设置或者清空
key
的
value(
字符串
)
在
offset
处的
bit
值。
setbit embstr raw int
#
动态字符串 能够节约内存
SETBIT key offset value
#
返回
key
对应的
string
在
offset
处的
bit
值
GETBIT key offset
#
统计字符串被设置为
1
的
bit
数
.
BITCOUNT key
1.2 存储结构
字符串长度小于等于20且能转成整数,则使用int存储;
字符串长度小于等于40,则使用embstr存储;
字符串长度大于44,则使用raw存储;
1.3 应用
对象存储:
用于极少修改的对象,对象属性字段很少改变的时候,类似于这种:
累加器:
#
统计阅读数 累计加
1
incr reads
#
累计加
100
incrby reads
100
分布式锁:
#
加锁 加锁 和 解析
redis
实现是 非公平锁
ectd zk
用来实现公平锁
#
阻塞等待 阻塞连接的方式
#
介绍简单的原理: 事务
setnx lock
1
#
不存在才能设置 定义加锁行为 占用锁
setnx lock uuid
# expire 30
过期
set
lock uuid nx ex
30
#
释放锁
del lock
if
(get(lock)
==
uuid)
del(lock);
位运算:
#
月签到功能
10001
用户
id 202106 2021
年
6
月份的签到
6
月份的第
1
天
setbit sign:10001:202106
1 1
#
计算
2021
年
6
月份 的签到情况
bitcount sign:10001:202106
#
获取
2021
年
6
月份 第二天的签到情况
1
已签到
0
没有签到
getbit sign:10001:202106
2
2. list类型
双向链表结构,首尾查找时间复杂度为O(1),中间位置的查找时间复杂度为O(n);
列表中数据压缩依据:
元素长度小于48,不压缩;
元素压缩前后长度差不超过 8,不压缩;
2.1 基础命令
#
从队列的左侧入队一个或多个元素
LPUSH key value [value ...]
#
从队列的左侧弹出一个元素
LPOP key
#
从队列的右侧入队一个或多个元素
RPUSH key value [value ...]
#
从队列的右侧弹出一个元素
RPOP key
#
返回从队列的
start
和
end
之间的元素
0, 1 2
负索引
LRANGE key
start
end
#
从存于
key
的列表里移除前
count
次出现的值为
value
的元素
# list
没有去重功能
hash set zset
LREM key count value
#
它是
RPOP
的阻塞版本,因为这个命令会在给定
list
无法弹出任何元素的时候阻塞连接
BRPOP key timeout
#
超时时间
+
延时队列
redis为请求回应机制,当服务器发送请求,redis必须做出回应,当list为空时,brpop list会发生阻塞,redis不会产生回应,只有当list中有数据时,brpop list会立即返回。
s1发送brpop list 0阻塞,s2 push value,s1收到返回。
2.2 存储结构
/* Minimum ziplist size in bytes for attempting compression. */#define MIN_COMPRESS_BYTES 48/* quicklistNode is a 32 byte struct describing a ziplist for a quicklist.* We use bit fields keep the quicklistNode at 32 bytes.* count: 16 bits, max 65536 (max zl bytes is 65k, so max count actually <32k).* encoding: 2 bits, RAW=1, LZF=2.* container: 2 bits, NONE=1, ZIPLIST=2.* recompress: 1 bit, bool, true if node is temporary decompressed forusage.* attempted_compress: 1 bit, boolean, used for verifying during testing.* extra: 10 bits, free for future use; pads out the remainder of 32 bits */typedef struct quicklistNode {struct quicklistNode * prev ;struct quicklistNode * next ;unsigned char * zl ;unsigned int sz ; /* ziplist size in bytes */unsigned int count : 16 ; /* count of items in ziplist */unsigned int encoding : 2 ; /* RAW==1 or LZF==2 */unsigned int container : 2 ; /* NONE==1 or ZIPLIST==2 */unsigned int recompress : 1 ; /* was this node previous compressed? */unsigned int attempted_compress : 1 ; /* node can't compress; too small*/unsigned int extra : 10 ; /* more bits to steal for future usage */} quicklistNode ;typedef struct quicklist {quicklistNode * head ;quicklistNode * tail ;unsigned long count ; /* total count of all entries in allziplists */unsigned long len ; /* number of quicklistNodes */int fill : QL_FILL_BITS ; /* fill factor for individualnodes */unsigned int compress : QL_COMP_BITS ; /* depth of end nodes not tocompress;0=off */unsigned int bookmark_count : QL_BM_BITS ;quicklistBookmark bookmarks [];} quicklist ;
2.3 应用
栈(先进后出)
LPUSH + LPOP# 或者RPUSH + RPOP
队列(先进先出)
LPUSH + RPOP# 或者RPUSH + LPOP
阻塞队列(blocking queue)
LPUSH + BRPOP# 或者RPUSH + BLPOP
异步消息队列
操作与队列一样,但是在不同系统间;生成者和消费者;
获取固定窗口记录
#往队列中push数据
lpush list value
#从左开始裁剪前50个数据
ltrim list 0 49
lrange list 0 -1
3.hash
散列表,在很多高级语言当中包含这种数据结构;
c++
unordered_map
通过
key
快速索引
value
;一般存储属性经常改变的对象。
3.1 基础命令
# 获取 key 对应 hash 中的 field 对应的值HGET key field# 设置 key 对应 hash 中的 field 对应的值HSET key field value# 设置多个 hash 键值对HMSET key field1 value1 field2 value2 ... fieldn valuen# 获取多个 field 的值HMGET key field1 field2 ... fieldn# 给 key 对应 hash 中的 field 对应的值加一个整数值HINCRBY key field increment# 获取 key 对应的 hash 有多少个键值对HLEN key# 删除 key 对应的 hash 的键值对,该键为 fieldHDEL key field
3.2 存储结构
节点数量大于512(hash-max-ziplist-entries)或所有字符串长度大于64(hash-max-ziplist-value),则使用dict实现;
节点数量小于等于512且有一个字符串长度小于64,则使用ziplist实现;
3.3 应用
存储对象
hmset hash:10001 name mark age 18 sex male# 与 string 比较set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:18}'# 假设现在修改 mark 的年龄为 19 岁# hash :hset hash:10001 age 19# string:get hash:10001# 将得到的字符串调用 json 解密,取出字段,修改 age 值# 再调用 json 加密set hash:10001 '{["name"]:"mark",["sex"]:"male",["age"]:19}'
购物车
# 将用户 id 作为 key# 商品 id 作为 field# 商品数量作为 value# 注意:这些物品是按照我们添加顺序来显示的;# 添加商品:hmset MyCart:10001 40001 1 cost 5099 desc " 戴尔笔记本 14-3400"lpush MyItem:10001 40001# 增加数量:hincrby MyCart:10001 40001 1hincrby MyCart:10001 40001 -1 // 减少数量 1# 显示所有物品数量:hlen MyCart:10001# 删除商品:hdel MyCart:10001 40001lrem MyItem:10001 1 40001# 获取所有物品:lrange MyItem:10001# 40001 40002 40003hget MyCart:10001 40001hget MyCart:10001 40002hget MyCart:10001 4000s et
4.set
4.1 基础命令
# 添加一个或多个指定的 member 元素到集合的 key 中SADD key member [member ...]# 计算集合元素个数SCARD key# SMEMBERS keySMEMBERS key# 返回成员 member 是否是存储的集合 key 的成员SISMEMBER key member# 随机返回 key 集合中的一个或者多个元素,不删除这些元素SRANDMEMBER key [count]# 从存储在 key 的集合中移除并返回一个或多个随机元素SPOP key [count]# 返回一个集合与给定集合的差集的元素SDIFF key [key ...]# 返回指定所有的集合的成员的交集SINTER key [key ...]# 返回给定的多个集合的并集中的所有成员SUNION key [key ...]
4.2 存储结构
元素都为整数且节点数量小于等于
512
(
set-max-intset-entries
),则使用整数数组存储;
元素当中有一个不是整数或者节点数量大于
512
,则使用字典存储;
4.3 应用
抽奖
# 添加抽奖用户sadd Award:1 10001 10002 10003 10004 10005 10006sadd Award:1 10009# 查看所有抽奖用户smembers Award:1# 抽取多名幸运用户srandmember Award:1 10# 如果抽取一等奖 1 名,二等奖 2 名,三等奖 3 名,该如何操作?srandmember Award:1srandmember Award:1 2srandmember Award:1 3
共同关注
sadd follow:A mark king darren mole vicosadd follow:C mark king darrensinter follow:A follow:C
推荐好友
sadd follow:A mark king darren mole vicosadd follow:C mark king darren# C 可能认识的人:sdiff follow:A follow:C
5. zset
有序集合;用来实现排行榜;值是有序的且是唯一的;
5.1 基础命令
# 添加到键为 key 有序集合( sorted set )里面ZADD key [NX|XX] [CH] [INCR] score member [score member ...]# 从键为 key 有序集合中删除 member 的键值对ZREM key member [member ...]# 返回有序集 key 中,成员 member 的 score 值ZSCORE key member# 为有序集 key 的成员 member 的 score 值加上增量 incrementZINCRBY key increment member# 返回 key 的有序集元素个数ZCARD key# 返回有序集 key 中成员 member 的排名ZRANK key member# 返回存储在有序集合 key 中的指定范围的元素 order by id limit 1,100ZRANGE key start stop [WITHSCORES]# 返回有序集 key 中,指定区间内的成员 ( 逆序 )ZREVRANGE key start stop [WITHSCORES]
5.2 存储结构
节点数量大于
128
或者有一个字符串长度大于
64
,则使用跳表(
skiplist
);
节点数量小于等于
128
(
zset-max-ziplist-entries
)且所有字符串长度小于等于
64
(
zset-max
ziplist-value
),则使用
ziplist
存储;
数据少的时候,节省空间;
$O(n)$
数量多的时候,访问性能;
$O(1)$ or $O(log_{2}{n})$
5.3 应用
百度热搜
zincrby hot:20240712 1 100zincrby hot:20240712 1 101zincrby hot:20240712 1 102zincrby hot:20240712 1 103zincrby hot:20240712 1 104zincrby hot:20240712 1 105zrevrange hot:20240712 0 5
延时队列
将消息序列化成一个字符串作为
zset
的
member
;这个消息的到期处理时间作为
score
,然后用
多个线程轮询
zset
获取到期的任务进行处理。
分享一个学习链接,有需要的同学可以看一下:
https://xxetb.xetslk.com/s/3yNycZ