一、五大基本数据类型
1.1 String字符串类型
1、常用命令
#=================添加操作、删除操作、查询操作=============
cj:15>set key1 7/25 # 新增一个key-value
"OK"
cj:15>del key1 # 删除一个key-value
"1"
cj:15>set key2 Tuesday
"OK"
cj:15>get key2 # 获取value值
"Tuesday"
cj:15>append key2 ", OMG" # 追加字符串,返回追加后的字符串长度
"12"
cj:15>get key2
"Tuesday, OMG"
cj:15>append key3 "I'm a new key" # 如果向一个不存在的key去追加,相当于set一个新的
"13"
cj:15>get key3
"I'm a new key"
cj:15>strlen key3 # 获取字符串长度
"13"
cj:15>set key4 Wednesday
"OK"
cj:15>expire key4 10 # 给key4设置过期时间,单位:秒
"1"
cj:15>ttl key4 # time to live ,还剩多少生命值,单位:秒
"3"
cj:15>ttl key4 # 当key过期时,ttl一直保持为-2
"-2"
cj:15>ttl key4
"-2"
cj:15>type key4 # 查无此键
"none"
cj:15>type key3 # 返回value类型
"string"
cj:15>incr key3 # 自增操作必须用在int上
"ERR value is not an integer or out of range"
cj:15>set integerKey 5
"OK"
cj:15>incr integerKey # 自增1
"6"
cj:15>incrby integerKey 3 # 自增规定步长
"9"
cj:15>decr integerKey # 自减1
"8"
cj:15>decrby integerKey 2 # 自减规定步长
"6"
cj:15>set key4 "hello,morning!"
"OK"
cj:15>getrange key4 0 5 # 返回字符串[0,5]范围内的字符串
"hello,"
cj:15>getrange key4 0 -1 # 返回完整字符串,相当于get key4命令
"hello,morning!"
cj:15>setrange key4 0 good, # 替换指定位置开始的字符串
"14"
cj:15>get key4
"good,,morning!"
cj:15>setex key5 30 "set with expire" # setex=set with expire,新建键值对的同时设定过期时间
"OK"
cj:15>ttl key5
"27"
cj:15>setnx key5 "newKey5" # setnx=set if not exits,新建键值对的时候会判断是否已经存在,如果存在则不会覆盖(多用于分布式锁/乐观锁)
"0"
cj:15>get key5 # 发现并没有被新的值覆盖
"set with expire"
cj:15>set key6 "original" # 对比单纯的set命令
"OK"
cj:15>set key6 "new"
"OK"
cj:15>get key6 # 新的值覆盖旧的值
"new"
cj:15>
批量操作:
cj:15>mset k1 v1 k2 v2 k3 v3 # 批量设置key-value
"OK"
cj:15>mget k1 k2 k3 # 批量获取
1) "v1"
2) "v2"
3) "v3"
cj:15>msetnx k1 v2 k4 v4 #批量设置,是一个原子操作,和事务一样,要么都成功要么都失败。因为k1已经存在了,所以整个操作失败,即使k4不存在也不会set成功。
"0" # 返回0,不成功
cj:15>getset k1 v1-1 # 先get再set,这样方便我们阅读
"v1"
cj:15>get k1
"v1-1"
cj:15>getset k5 v5 # 当get的值不存在时,返回null
null
cj:15>get k5
"v5"
redis可以定义对象
方式(一):以JSON格式(其实就是key-value格式)保存一个对象
cj:15>set user:1 {name:dd,age:25} # 1号用户
"OK"
cj:15>keys *
1) "k1"
2) "k2"
3) "user:1"
4) "k3"
5) "k5"
cj:15>get user:1
"{name:dd,age:25}"
方式(二): 把对象的两个属性定义成两个key
cj:15>get user:1
"{name:dd,age:25}"
cj:15>mset user:1:name dd user:1:age 4
"OK"
cj:15>mget user:1:name user:1:age
1) "dd"
2) "4"
# 此种方式实际上定义了两个key
cj:15>keys *
1) "user:1:age"
2) "user:1:name"
注意,如果采用第一种方式,那么无法单独取出字段哦~
cj:15>set user:1 {name:dd,age:25}
"OK"
cj:15>mget user:1:name user:1:age # 此种方式不可获得如上定义的name和age字段
1) null
2) null
cj:15>keys *
1) "user:1"
cj:15>get user:1 # 只能通过全部get的方式
"{name:dd,age:25}"
2、使用场景
数字int类型的string作为计数器,比如统计文章的浏览量,用incr key命令实现浏览量+1。你想啊浏览量这个东西如果每次+1你都写一次磁盘太浪费资源了,所以就先写到缓存里,再定时刷进磁盘。
比如统计粉丝数量,用decr key实现粉试数量-1。可以进行如下定义“id为794329用户的粉丝量为2”
set user:794329 {fansNum:2}
1.2 List类型
- list在redis里其实是一个链表,所以才有头插和尾插操作。当删掉了最后一个元素时,这个链表也就不存在了
- 通过给list设置“先进先出”等规则,可以将list当做消息队列、堆、栈、阻塞队列使用。
- 所有命令以“L”开头
- list中的值是可以重复的,set不可以重复
1、常用命令
#####################增加操作、查看操作############################
cj:15>LPUSH mylist string1 #LPUSH是头插法(自己画图感受)
"1"
cj:15>LPUSH mylist string2
"2"
cj:15>LPUSH mylist string3
"3"
cj:15>LPUSH mylist string3 # string类型不能有重复的key,但是list可以有重复的值
"4"
cj:15>LRANGE mylist 0 -1 # 打印全部的list,注意无法用get去获取全部的list
1) "string3"
2) "string3"
3) "string2"
4) "string1"
cj:15>LRANGE mylist 1 2 # 从左到右打印[1,2]区间的list
1) "string3"
2) "string2"
######################删除操作#######################
cj:15>RPUSH mylist right # 尾插法,插到最右边
"5"
cj:15>LPOP mylist # 删除最左边的元素
"string3"
cj:15>RPOP mylist # 删除最右边的元素
cj:15>LRANGE mylist 0 -1 # 先看一下有两个string3
1) "string3"
2) "string2"
3) "string1"
4) "string3"
cj:15>Lrem mylist 1 string3 # 指定下标删除元素“1”代表移除从左数1个string3
"1"
cj:15>LRANGE mylist 0 -1
1) "string2"
2) "string1"
3) "string3"
###################其他常见操作###############
cj:15>Lindex mylist 0 # 下标为0的元素
"string2"
cj:15>Lindex mylist 1
"string1"
cj:15>Lindex mylist 4 # 下标为4没有元素
null
cj:15>Llen mylist # list长度
"3"
cj:15>Ltrim mylist 1 2 # 截取[1,2]部分,剩下的直接扔了
"OK"
cj:15>LRANGE mylist 0 -1
1) "string1"
2) "string3"
cj:15>rpoplpush mylist newlist #弹出mylist最右边元素,放到newlist最左边。如果没有newlist那就自动创建
"string3"
cj:15>get newlist # 不能用get哦
"WRONGTYPE Operation against a key holding the wrong kind of value"
cj:15>lrange newlist 0 -1
1) "string3"
cj:15>lpop newlist # 删掉newlist所有元素
"string3"
cj:15>exists newlist # 那么这个newlist也就不存在了(因为list底层是一个链表)
"0"
cj:15>exists mylist
"1"
###############指定下标更新操作################
cj:15>lset mylist 0 "heihei" # 替换下标为0的元素
"OK"
cj:15>lrange mylist 0 -1
1) "heihei"
2) "string3"
3) "string2"
4) "string1"
cj:15>lset mylist 8 "OK?" # 替换下标不存在的元素,报错
"ERR index out of range"
###################插入操作########################
cj:15>LINSERT mylist after "string3" "after3" # after表示插入string3的后面(从左到右)
"5"
cj:15>LINSERT mylist before "string1" "before1" # before表示插入string1的前面(从左到右)
"6"
cj:15>lrange mylist 0 -1
1) "heihei"
2) "string3"
3) "after3"
4) "string2"
5) "before1"
6) "string1"
2、使用场景
模拟消息队列。甚至可以用ltrim命令截取部分信息。
1.3 set类型
1、常用命令
######################添加操作################
cj:15>sadd myset 1
"1"
cj:15>sadd myset 2
"1"
cj:15>sadd myset 4
"1"
cj:15>sadd myset 3
"1"
cj:15>sadd myset 8
"1"
cj:15>sadd myset 0110
"1"
####################查看操作####################
cj:15>smembers myset # 并不是按照添加的顺序输出的,说明set的底层是用C++写的hashmap
1) "8"
2) "4"
3) "2"
4) "1"
5) "0110"
6) "3"
cj:15>scard myset # set的元素个数
"6"
cj:15>SISMember myset 9 # 是否是set的元素,“1”表示是
"0"
cj:15>SISMember myset 8
"1"
#######################删除操作#################
cj:15>srem myset 3
"1"
cj:15>srandmember myset # 随机抽取一个元素(抽奖)
"2"
cj:15>srandmember myset
"0110"
cj:15>srandmember myset
"1"
cj:15>spop myset # 随机删除一个元素
"2"
cj:15>spop myset 3 # 随机删除3个元素
1) "4"
2) "1"
3) "0110"
cj:15>smove myset newset 8 # 把元素“8”从myset移动到newset中去,没有newset就新建一个
"1"
cj:15>smembers newset
1) "8"
集合特有的一些操作:求并集,交集,差集
cj:15>sadd myset1 a
"1"
cj:15>sadd myset1 b
"1"
cj:15>sadd myset1 c
"1"
cj:15>sadd myset2 aa
"1"
cj:15>sadd myset2 bb
"1"
cj:15>sadd myset2 c
"1"
cj:15>smembers myset1
1) "b"
2) "c"
3) "a"
cj:15>smembers myset2
1) "bb"
2) "aa"
3) "c"
cj:15>SUNION myset1 myset2 # 求并集
1) "b"
2) "c"
3) "a"
4) "aa"
5) "bb"
cj:15>Sdiff myset1 myset2 # 求myset1相对于myset2的差集
1) "b"
2) "a"
cj:15>Sinter myset1 myset2 # 求交集
1) "c"
2、使用场景
- 微博的共同关注
- 关注的人是不重复且无序的,刚好用set去存储。然后求两个set的交集
- 推荐好友
- 求你的关注列表这个set和你关注的某个人他的关注列表这个set的交集
1.4 Hashmap哈希类型
- 本质和string类型没有区别。也是key-value,只不过是一堆key-value存在一个hashmap里。直接理解成java里的new HashMap<String,Object>,同样key不能重复
- 最佳应用:存储变更的数据,尤其是用户的信息
- 对象存储用哈希!虽然string也可以存对象,但是不是最佳方法(太麻烦了!)
1、常用命令
##################增加、查看操作####################
cj:15>hset myhash k1 v1 k2 v2 k3 v3 #hset等同于hmset,可以同时存储多对key-value
"3"
cj:15>hget myhash k1
"v1"
cj:15>hmget myhash k1 k2 k3 # 批量查看
1) "v1"
2) "v2"
3) "v3"
cj:15>hgetall myhash # 查看所有键值对
1) "k1"
2) "v1"
3) "k2"
4) "v2"
5) "k3"
6) "v3"
##################删除操作###############
cj:15>hdel myhash k2
"1"
cj:15>hgetall myhash
1) "k1"
2) "v1"
3) "k3"
4) "v3"
cj:15>hlen myhash # 键值对个数
"2"
cj:15>hexists myhash k1 # 是否存在某个key
"1"
cj:15>hexists myhash k2
"0"
#############等同于java中hashmap的keyset()和values()方法#############
cj:15>hkeys myhash # 所有key
1) "k1"
2) "k3"
cj:15>hvals myhash # 所有value
1) "v1"
2) "v3"
##################测试自增自减############
cj:15>hset myhash k5 5
"1"
cj:15>hincrby myhash k5 1 # 自增特定步长
"6"
cj:15>hincrby myhash k5 -1 # 自减特定步长
"5"
cj:15>hdecrby myhash k5 1 # 没有hdecrby命令,自减的话用自增命令把值设为负数
"ERR unknown command `hdecrby`, with args beginning with: `myhash`, `k5`, `1`, "
cj:15>hdecr myhash k5 # 也没有自-1命令,只有特定步长命令
"ERR unknown command `hdecr`, with args beginning with: `myhash`, `k5`, "
cj:15>hincr myhash k5 # 也没有自+1命令,只有特定步长命令
"ERR unknown command `hincr`, with args beginning with: `myhash`, `k5`, "
###################修改操作#####
cj:15>hsetnx myhash k5 7 # hsetnx表示已经存在就不要添加了
"0"
cj:15>hset myhash k5 7 # 但是可以修改/覆盖
"0"
cj:15>hgetall myhash
1) "k1"
2) "v1"
3) "k3"
4) "v3"
5) "k5"
6) "7" # 修改成功
###################存储java对象###################
cj:15>hset userMap name jj age 20
"2"
cj:15>hgetall userMap
1) "name"
2) "jj"
3) "age"
4) "20"
2、使用场景
储变更的数据(java对象),尤其是用户的信息
1.5 Zset类型
- 底层是linkedHashMap,把元素添加进去以后,哈希表给自动排好序了
- 有序的set,可以通过score这个指标去排序。有一些set的命令不能直接拿来用哦,比如smembers不能直接变成zmembers去用
- 要求我们向zset中添加元素时,带着score这个指标,用来作为排序的标准
1、常用命令
###################添加操作####################
cj:15>zadd salaryset 5000 qq 3000 dd 8000 mm 500 kk
"4"
####################(升序、降序)查看操作##################
cj:15>zrange salaryset 0 -1 # 自动按照工资的升序排序(kk最低,mm最高)
1) "kk"
2) "dd"
3) "qq"
4) "mm"
cj:15>zrevrange salaryset 0 -1 # 自动按照工资的降序排序
1) "mm"
2) "qq"
3) "dd"
4) "kk"
cj:15>zrevrangebyscore salaryset +inf -inf #按照[正无穷,负无穷]区间降序排列,注意前面的参数一定要大于后面的参数
1) "mm"
2) "qq"
3) "dd"
4) "kk"
cj:15>zrevrangebyscore salaryset +inf -inf withscores # 并输出对应的score
1) "mm"
2) "8000"
3) "qq"
4) "5000"
5) "dd"
6) "3000"
7) "kk"
8) "500"
cj:15>zrangebyscore salaryset -inf 7000 withscores # 升序,只看7000以下的
1) "kk"
2) "500"
3) "dd"
4) "3000"
5) "qq"
6) "5000"
########################删除操作##################3
cj:15>zrem salaryset kk
"1"
######################统计元素个数操作####################
cj:15>zcard salaryset # 统计所有元素个数
"3"
cj:15>zcount salaryset 300 600 # 统计score在[300,600]这个区间内所有元素个数。至于开区间和闭区间的设置自己去查哦!开区间可能参数要(300 600)这样写
"0"
cj:15>zcount salaryset 300 7000
"2"
2、使用场景
班级成绩表排序,消息权重排序(重要消息权重大)、工资表排序
二、3大特殊数据类型
2.1 Geospatial类型——周围的人
1、只有6个命令
# 语法: geoadd key的名称 经度 纬度 给坐标起个名字
# 注意一定要先经度再纬度,不然范围错了会报错
cj:11>geoadd china:city 116.40 39.90 beijing
"1"
cj:11>geoadd china:city 121.47 31.23 shanghai
"1"
# 查看
cj:11>geopos china:city beijing shanghai
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "121.47000163793563843"
2) "31.22999903975783553"
# 计算两个城市间距离 单位:m米 km千米 mi英里 ft英尺
cj:11>geodist china:city beijing shanghai km
"1067.3788"
GEORAIUDS命令和GEORADIUSBYMEMBER命令的区别:
- 这两个命令都是以指定位置为中心,画个圆。
- GEORADIUS的参数是指定经纬度,通常用于“寻找周围的人”。
- GEORADIUSBYMEMBER的参数是位置集合里的某个成员
# 语法 GEORADIUS 要查找的集合的key值 经度 纬度 半径 半径的单位
cj:11>GEORADIUS china:city 110 30 500 km
1) "chongqing"
2) "xian"
# withdist参数打印距离,withcoord 参数打印经纬度,count 1参数指定要查找几个。比如附近1000km的人有200个,但我们只想看离我们最近的100个
cj:11>GEORADIUS china:city 110 30 500 km withdist withcoord count 1
1) 1) "chongqing"
2) "342.2210"
3) 1) "106.49899989366531372"
2) "29.52000010403299513"
# 语法 GEORADIUSBYMEMBER 要查找的集合的key值 集合里某个位置的名字 半径 半径的单位
cj:11>GEORADIUSBYMEMBER china:city beijing 1000 km withdist
1) 1) "beijing"
2) "0.0000"
2) 1) "xian"
2) "910.8533"
GEOHASH命令就是将位置转换成哈希值,基本上用不到这个命令。
2、使用场景
我的位置、周围的人、打车距离的计算