redis数据类型
redis的数据类型是针对value的, key是一个对象,里面有个type和encoding
- type:类型,一般都是字符串string
- encoding:字符集
启动redis
./redis-server &
: 以后台程序方式运行redis./redis-server /etc/redis/6379.conf
:指定配置文件运行redis-cli -p 6380
: 指定端口号运行
redis-cli命令 连接到服务端
redis默认有16个库,从0开始到15,每个库都是独立的数据,互不共享,连接之前下先进入/.../redis-3.0.6/src/
目录;
redis-cli
:默认连到6379redis-cli -p 6380
:连接到6380端口的redisredis-cli -n 1
// 连接到哪个库,默认第0个库redis-cli -p 6379 -a root
// -p指定端口,-a指定认证密码,redis不需要用户名,redis服务是主机加密码来进行认证的/redis-cli –p 6379 --raw
(终端展示中文,不加--raw
时展示的是字节码:xb0\xe4\xb8\x9c)
连接密码
如果配置了密码,在连接到reids进行操作时会提示错误(error) NOAUTH Authentication required.
,遇到这种问题,输入以下命令即可解决
# password是你的密码,比如我的密码是123,那么命令为:auth 123
auth pwssword
所有命令
keys *
:查看所有的key值flushdb
:清空所有数据,尽量不要使用这个命令flushall
:清空所有数据,尽量不要使用这个命令clear
:清屏set key111:1 hello
: 设置到1号库,key111,value为helloget key111:1
:获取1号库,key为key111的值select 8
:进入8号库help
:查看帮助命令type k1
:查看k1的value数据类型exit
:退出redishelp @string
:查看string数据类型的所有命令help @list
:查看list数据类型的所有命令help @hash
:查看hash数据类型的所有命令help @set
:查看set数据类型的所有命令help @sortset
:查看sortset数据类型的所有命令help set
:查看某个命令的使用方法,比如:help rpush
string 数据类型命令
set key value
:设置值get key
:获取指定key的值getset k1 yexindong
: 取回老的值,并且设置新值set k1 hello nx
:nx表示当k1这个key不存在的时候才可以设值,如果已存在则不允许设值,分布式锁的时候可以使用这个功能set k1 hello xx
:xx表示只能更新,当k1这个key存在的时候才能更新值,不存在时不允许设值;mset k3 hello k4 would
:同时设置多个key-valuemget k3 k4
:同时获取多个key的valuemsetnx k1 a k2 b
:同时设置多个值,并且key不存在的时候才可以设值,如果已存在则不允许设值,这是个原子性操作,只要有一个失败的,那么全都失败,跟事务一样,要么一起成功,要么一起失败append k1 "world"
:在k1上追加字符串后在重新设回k1,如果一开始k1的值是 hell,执行完append k1 “world”命令后,k1的值就是hello world了getrange k1 6 10
:相当于java的substring(6,10)方法getrange k1 6 -1
: 获取k1字符串第6个下标到最后一个字符之间的内容setrange k1 6 yexindong
:修改第6个下标之后的所有值,如果k1的初始值为hello world,执行完这个命令后会变成 hello yexindongstrlen k1
:统计k1字符串的长度,和java的length方法一样set key value ex 20
:设置一个自动过期的key,20秒后自动过期,set key value px 20
:设置一个自动过期的key,20毫秒后自动过期,ttl key
: 查看一个key的有效期,返回负数-2以上表示已过期,-1是永久存在,不过期expire k4 50
:给一个key设置过期时间,不管key是否存在都可以设置;EXPIREAT runoobkey 1293840000
:设置key在指定时间后过期,这个时间需要先转成long类型时间戳;
数值的操作
set knum 99.01
:设置数字或小数incr k1
: k1的数值基础上+1,前提value必须是int,支持小数incrby k1 22
:k1的数值基础上+22,前提value必须是int,支持小数decr k1
:k1的数值基础上减1,前提value必须是int,支持小数decrby k1 10
:k1的数值基础上减10,前提value必须是int,支持小数
String的set命令实现hash功能
# yexindong为外层的key值,冒号后面为value中的key值;一个用户有多个属性,就可以这么表示;
set yexindong::id 1 // yexindong的用户id
set yexindong::age 28 // yexindong的年龄
set yexindong::name '叶新东' // yexindong的中文名称
set yexindong::url 'http://xxx.com' //yexindong的主页
# 查看所有值,展示yexindong这个key下面的所有key值,只是key,没有value;
keys yexindong*
bitmap 位图操作
setbit
将二进制的第二位设为1,此时kbit的二进制为0100
,转为sacii码就是@
setbit k2 1 1
127.0.0.1:6379> get k2
@
在K2的基础上在设置,把第7位也设为1,此时的二级制就是0100 0001
,转为sacii码就是A
127.0.0.1:6379> setbit k2 7 1
127.0.0.1:6379> get k2
A
bitpos 命令
bitpos命令用于查找字节的某个位的值,就拿上面的二进制来举例0100 0001
# 我要找k2二进制中 1 是不是出现在第0个字节的第1个位置上
bitpos k2 1 0 1
1
# 我要找k2二进制中 1 是不是出现在第0个字节的第7个位置上
bitpos k2 1 0 7
1
# 我要找k2二进制中 1 是不是出现在第0个字节的第6个位置上,肯定找不到的,所以返回-1
bitpos k2 1 0 67
-1
bitcount
统计二进制中出现了几个1,
以下例子统计k2的二进制中第0个字节和第1个字节之间出现了几个1
bitcount k2 0 1
2
bitop 按位与、按位或运算
将k1和k2的二进制进行按位与运算后将结果放到andkey中
bitop and andkey k1 k2
将k1和k2的二进制进行按位或运算后将结果放到orkey中
bitop or orkey k1 k2
bitmap 有什么用?
比如有这样一个场景,要统计用户一年中的登录天数,并且要统计某个用户在一年中某个期间登录了多少天,那么就可以用bitmap,这种需求,虽然用关系型数据库也能实现,但是会占用大量的磁盘空间,用位图存储可以节省大量空间;
用二进制来表示用户登录的天数,可以这么干,
#第一天登录了,命令如下
setbit zhangsan 0 1
#用二进制表示如下
1000
#第8天登录了,命令如下
setbit zhangsan 7 1
#用二进制表示如下
0000 0001
#一年365天,在第364天登录了,命令如下
setbit zhangsan 363 1
#用二进制表示如下,其中的1在二进制的第363个位置
00000.....10
接下来,因为一个字节是8个位,所以我们可以统计某个用户头16天里面登录了几天,可以这么干
bitcount zhangsan 0 1
正反向索引
可以通过反向索引统计某个用户一年中最后16天登录了几天,可以这么干,-1表示倒数第一个字节,-2表示倒数第二个字节;
bitcount zhangsan -1 -2
一个统计头16天,一个统计尾16天,简单的2个命令就实现了,是不是很简单呢?
list (链表)
- list是一个双向链表,每个节点除了自身元素外,还维护了2个指针,一个指向上一个节点(pre),另一个指向下一个节点(next)
- 也是一个双端队列,有一个head变量指向队头,还一个tail变量指向队尾;
- 利用
lpush
和lpop
命令组合可实现栈的功能(先入后出、后入先出) - 利用
rpush
和rpop
命令组合可实现队列功能(先入先出、后入后出) - 利用
lindex
和lset
可实现数组功能
常用命令
lpush 头插
前面的l表示left ,从左往右将数据添加到链表中,也就是头插法,就拿下面的例子来说
lpush k1 a b c d e f
# 将 a b c d e f 依次在k1的头部插入
#添加a时k1的数据为 a
#添加b时k1的数据为 b a
#添加c时k1的数据为 c b a
#添加d时k1的数据为 d c b a
#添加e时k1的数据为 e d c b a
#添加f时k1的数据为 f e d c b a
rpush 尾插
前面的r表示right,从右往左将数据添加到链表中,也就是尾插法,举例
rpush k2 a b c d e f
# 将 a b c d e f 依次在k2的尾部插入
#添加a时k2的数据为 a
#添加b时k2的数据为 a b
#添加c时k2的数据为 a b c
#添加d时k2的数据为 a b c d
#添加e时k2的数据为 a b c d e
#添加f时k2的数据为 a b c d e f
lrange命令
LRANGE k1 0 -1 //打印k1列表的所有值,打印从0开始到最后一个(-1)元素的值;
LRANGE k1 -2 -1 // 打印列表尾部的最后2个元素值
LRANGE k1 0 0 // 打印列表头部第一个元素值
LRANGE k1 0 1 // 打印列表头部的头2个元素值
lindex命令
lindex命令的功能是取出list中某个下标的值
lindex k1 2 // 获取第二个元素的值
lindex k1 -1 // 获取最后一个元素的值
lpop
lpop的功能是移除头部的第一个元素
比如k2的列表内容为: a b c
lpop k2 // 取出头部第一个元素a,此时还剩下b 和c
lpop k2 // 取出头部第一个元素b,此时还剩下c
lpop k2 // 取出头部第一个元素c,此时列表为空
rpop
rpop的功能是移除尾部第一个元素,和队列的出队一样
比如k2的列表内容为: a b c
rpop k2 // 取出尾部第一个元素c,此时还剩下a 和b
rpop k2 // 取出尾部第一个元素b,此时还剩下a
rpop k2 // 取出尾部第一个元素a,此时列表为空
blpop
b
表示blocking,是阻塞的意思,l表示left
,blpop命令是以阻塞的方式移除队头的第一个元素,如果list中没有元素,则进入阻塞状态,等到有值为止
blpop kbs 2 // 获取key为kbs的头部第一个元素,如果队列为空,阻塞等待2秒,2秒后若还没有其他线程插入元素,则自动退出
blpop kbs 0 //获取key为kbs的头部第一个元素,如果队列为空,一直阻塞直到有人塞值为止
brpop
与blpop
命令同理,区别是blpop
移除头部元素,brpop
移除尾部元素
lrem
lren 用于删除元素
# 比如k3的list内容为 1 a 2 a 3 a
lrem k3 2 a // 删除前2个a
删除后的内容为: 1 2 3 a
lrem k3 1 a // 删除前一个a
# 比如k4的list内容为 1 a 2 a 3 a
lrem k3 -2 a // 删除最后2个a,删除后的内容为:1 a 2 3
lrem k3 -1 a // 删除最后的一个a
linsert
插入命令
# 比如k4目前的值为 a b c d
linsert k4 after a 1 // 往字符a后面插入1,执行命令后k4的值为:a 1 b c d
# 遇到有2个相同的字符怎么半?比如k5目前的值为 a 1 b c d 1
linsert k5 after 1 2 //往1后面插入2,执行命令后k5的值为:a 1 2 b c d 1;只会插入一次
# 比如k6目前的值为 a b c d
linsert k6 before a x // 在a前面插入x,执行命令后k6的值为:x a b c d
llen
统计list的元素个数
llen k5
LTRIM
和substring类似
# 比如我k7的list为: a b c d e f
ltrim k7 2 -1 // 截取第2个元素(元素从0开始)开始到末尾,执行命令后k7的值为:c d e f
# 比如我k7的list为: a b c d e f
ltrim k7 2 -2 // 截取第2个元素(元素从0开始)开始到倒数第二个元素的值,执行命令后k7的值为:c d e
hash
hash就想是java里面的hashMap,hash是key-value键值对格式的,就相当与是hashMap里面的value又是一个hashMap;
hash的lset命令
# yexindong是最外层的key,name是内存的key,值为:叶新东
hset yexindong name '叶新东' // 设置单个key-value
hset
hget
获取某个key的值
hget yexindong name // 获取yexindong的name属性
hget yexindong age // 获取yexindong的age属性
hmset 命令
hmset 用于同时设置多个key-value
// 设置yexindong 的性格(sex) 和 主页(url)
hmset yexindong sex 1 url 'http://xxx.com'
hmget 命令
同时获取多个key的值
hmget yexindong name sex
hkeys
获取某个key下面的所有key
hkeys yexindong
hvals
获取所有的value,不包括key
hvals yexindong
hgetall
获取所有的key-value键值对,
hgetall yexindong
HINCRBY 数值计算
可对hash中的数值进行计算,但仅限于整数,不能进行小数计算,此功能可用来计算详情页的点赞数量和收藏数量;
//将yexindong的age + 1
HINCRBY yexindong age 1
//将yexindong的age 减 2
HINCRBY yexindong age -2
HINCRBYFLOAT 小数计算
将yexindong的age + 0.5
HINCRBYFLOAT yexindong age 0.5
将yexindong的age 减1.5
HINCRBYFLOAT yexindong age -1.5
set
list和set的区别
- list有序,set无序
- list可以重复,set自动去重
sadd
添加元素,可以同时添加多个
sadd s1 1 2 3 4
smembers
遍历所有的元素
smembers s1
srem
删除元素
// 删除元素值为1 和 2的值
srem s1 1 2
sinter
sinter命令用于比较多个个key的交集部分
//比如有3个key,
//s1: 1 2 3 4
//s2: 3 4 5 6
//s3: 3 4 9 10
sinter s1 s2 s3 // 输出s1、s2、 s3 的的交集数据,结果为3 4
sinterstore
sinterstore命令用于将多个key的交集保存到指定的新key中
//比如有3个key,
//s1: 1 2 3 4
//s2: 3 4 5 6
//s3: 3 4 9 10
//将s1、s2、 s3 的的交集数据保存到scount中
sinterstore scount s1 s2
sunion
sunion 是将多个key中并集的提取出来并输出
//比如有2个key,
//s1: 1 2 3 4
//s2: 3 4 5 6
sunion s1 s2 // 输出结果为:1 2 3 4 5 6
sunionstore
sunionstore 是将多个key中并集的提取出来保存到新的key中
//比如有2个key,
//s1: 1 2 3 4
//s2: 3 4 5 6
sunionstore socunt s1 s2 // socunt结果为:1 2 3 4 5 6
sdiff 差集
差集指的是两个key之间 第一个key中元素减去两个key中的交集部分的结果
//比如有2个key,
//s1: 1 2 3 4
//s2: 3 4 5 6
sdiff s1 s2 // 输出结果为 1 2
sdiff s2 s1 // 输出结果为 5 6
SRANDMEMBER
SRANDMEMBER 用于返回集合中的随机元素,可以用来抽奖,
SRANDMEMBER有个count参数,
- 当count为正数时,返回一个count个数的数组,并且数组中的元素不会重复
- 当count为负数时,返回一个count个数的数组,数组中的元素可能会重复多次;
SRANDMEMBER s1 5 // 返回去重后的数组,元素不会重复
SRANDMEMBER s1 -10 // 返回数组,元素可能重复多次
SRANDMEMBER s1 0 // 返回空
spop
spop 用来抽取set集合中随机一个元素,抽出后,会从set集合中移除此元素;spop命令更适合用来年会抽奖使用,抽中之后就从集合中移除元素;
spop s1 // 每次随机抽一个元素并移除,就跟队列的出队一样
sorted set
有序的set,除了元素之外,还需要给出分值,分值是用来决定排序的;
在添加元素时,物理内存遵循左小右大
原则,比如我执行以下命令后,默认排序时zhangsan
是最小的,lisi
是最大的
zadd k1 5 zhangsan 6 xiaoming 2 lisi
其他命令
// 添加sorted set 元素,k1为key值,1 2 3 是分值,a b c是元素,每个分值对应一个元素1是a,2是b,3是c
zadd k1 1 a 2 b 3 c
// 添加的元素也可以是浮点数,但只能是浮点数和数字
zadd k2 1.1 a 2.2 b 3.3 c
// 打印所有的元素,按照添加时的顺序排列
zrange k2 0 -1
// 打印所有元素,按照分值进行升序排序
zrange k2 0 -1 withscores
// 根据分值范围获取元素,获取k2中 2 ~ 8分值范围的元素,如果你的分值有1 2 4 8,那么会打印出 2 4 8分值的元素;
zrangebyscore k2 2 8
// 获取分值最大的前2个元素
ZREVRANGE k2 0 1
// 通过元素获取分值
zscore k2 a
// 获取元素的默认排名,比如我添加命令为 zadd k2 7 a 8 b 9 c ,当我执行下面命令后结果为:2
zrank k2 b
//增加某个元素的分值,key为k2,将k2中b元素的分值增加2.5,比如我的添加命令为 zadd k2 8 b ,执行下面命令后元素b的分值为:10.5
zincrby k2 2.5 b // b元素的分值添加2.5
zincrby k2 -2.5 b // b元素的分值减去2.5
sorted set的并集、交集处理命令zubionstore
首先使用2个key,k1和k2,他们的内容为以下结果
zadd k1 60 zhangsan 20 lisi 100 wangwu
zadd k2 100 zhangsan 80 lisi 10 wangwu 66 zhaoliu 77 tianqi
统计2个key元素的和
这个命令相当于将2个key中相同的元素合并,将他们的分值相加,就跟mysql的sum()函数一样
// 执行命令-将相同元素的分值相加,将k1和k2统计出来的内容放到新的 sumkey 中(key值)
ZUNIONSTORE sumkey 2 k1 k2
(integer) 5
// 以下是打印的结果
127.0.0.1:6379> zrange sumkey 0 -1 withscores
1) "zhaoliu"
2) "66"
3) "tianqi"
4) "77"
5) "lisi"
6) "100"
7) "wangwu"
8) "110"
9) "zhangsan"
10) "160"
权重统计
权重统计需要加上关键字weights
// 注意后面多2个参数分别是1 0.5,
ZUNIONSTORE sumkey1 2 k1 k2 weights 1 0.5
// 查看结果
127.0.0.1:6379> zrange sumkey1 0 -1 withscores
1) "zhaoliu"
2) "33" // k1没有 zhaoliu ,k2的 zhaoliu 是66,得出权重公式为(66 * 0.5) =33
3) "tianqi"
4) "38.5" // k1没有 tianqi ,k2的 tianqi 是77,得出权重公式为(77 * 0.5) =38.5
5) "lisi"
6) "60" // k1的 lisi 是20,k2的 lisi 是80,得出权重公式为(20*1 + 80 * 0.5) = 60
7) "wangwu"
8) "105" // k1的 wangwu 是100,k2的wnagwu是10,得出权重公式为(100*1 + 10 * 0.5) = 105
9) "zhangsan"
10) "110" // k1 的zhangsan是60 ,k2的zhangsan是100,得出权重公式为(60*1 + 100 * 0.5) = 110
统计最大值
在2个key中取最大分值的元素,
最大值统计需要用到aggregate max
关键字
// 统计最大值,将结果放到sumkey2中
ZUNIONSTORE sumkey2 2 k1 k2 aggregate max
//以下是打印的结果
127.0.0.1:6379> zrange sumkey2 0 -1 withscores
1) "zhaoliu"
2) "66" // 最大值在k2里面
3) "tianqi"
4) "77" // 最大值在k2里面
5) "lisi"
6) "80" // 最大值在k2里面
7) "wangwu"
8) "100" // 最大值在k1里面
9) "zhangsan"
10) "100" // 最大值在k2里面
sorted set的排序是怎么实现的,它用了哪个数据类型实现
答案是 skip list(跳跃表)