redis基础

常用命令

127.0.0.1:6379> ping  #查看当前连接是否正常,正常返回PONG
PONG
127.0.0.1:6379> clear  #清楚当前控制台(为了更好的看到下面输入的命令)
127.0.0.1:6379> keys *  #查看当前库里所有的key
1) "db"
127.0.0.1:6379> FLUSHALL  #清空所有库的内容
OK
127.0.0.1:6379> keys * 
(empty array)
127.0.0.1:6379> set name dingdada  #添加一个key为‘name’ value为‘dingdada’的数据
OK
127.0.0.1:6379> get name  #查询key为‘name’的value值
"dingdada"
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set name1 dingdada2
OK
127.0.0.1:6379> get name1
"dingdada2"
127.0.0.1:6379> keys *  #查看当前库里所有的key
1) "name1"
2) "name"
127.0.0.1:6379> EXISTS name  #判断当前key是否存在
(integer) 1
127.0.0.1:6379> move name 1  #移除当前库1的key为‘name‘的数据
(integer) 1
127.0.0.1:6379> keys *
1) "name1"
127.0.0.1:6379> FLUSHALL  #再次清空所有库的内容
OK

## 多加几条数据 下面测试设置key的过期时间
127.0.0.1:6379> set name dingdada
OK
127.0.0.1:6379> set name1 dingdada1
OK
127.0.0.1:6379> set name2 dingdada2
OK
127.0.0.1:6379> EXPIRE name 15  #设置key为’name‘的数据过期时间为15秒 单位seconds
(integer) 1
127.0.0.1:6379> ttl name  #查看当前key为’name‘的剩余生命周期时间
(integer) 13
127.0.0.1:6379> ttl name
(integer) 12
127.0.0.1:6379> ttl name
(integer) 11
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) 6
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) 0
127.0.0.1:6379> ttl name  #如若返回-2,证明key已过期
(integer) -2
127.0.0.1:6379> get name    #再次查询即为空
(nil)
127.0.0.1:6379> type name1
string

String(字符串)
String是Redis中最常用的一种数据类型,也是Redis中最简单的一种数据类型。首先,表面上它是字符串,但其实他可以灵活的表示字符串、整数、浮点数3种值。Redis会自动的识别这3种值。

  1. 添加、查询、追加、获取长度,判断是否存在的操作
127.0.0.1:6379> set name dingdada  #插入一个key为‘name’值为‘dingdada’的数据
OK
127.0.0.1:6379> get name  #获取key为‘name’的数据
"dingdada"
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> keys *  #查看当前库的所有数据
1) "name"
127.0.0.1:6379> EXISTS name  #判断key为‘name’的数据存在不存在,存在返回1
(integer) 1
127.0.0.1:6379> EXISTS name1  #不存在返回0
(integer) 0
127.0.0.1:6379> APPEND name1 dingdada1  #追加到key为‘name’的数据后拼接值为‘dingdada1’,如果key存在类似于java中字符串‘+’,不存在则新增一个,类似于Redis中的set name1 dingdada1 ,并且返回该数据的总长度
(integer) 9
127.0.0.1:6379> get name1
"dingdada1"
127.0.0.1:6379> STRLEN name1  #查看key为‘name1’的字符串长度
(integer) 9
127.0.0.1:6379> APPEND name1 ,dingdada2  #追加,key存在的话,拼接‘+’,返回总长度
(integer) 19
127.0.0.1:6379> STRLEN name1
(integer) 19
127.0.0.1:6379> get name1
"dingdada1,dingdada2"
127.0.0.1:6379> set key1 "hello world!"  #注意点:插入的数据中如果有空格的数据,请用“”双引号,否则会报错!
OK
127.0.0.1:6379> set key1 hello world!  #报错,因为在Redis中空格就是分隔符,相当于该参数已结束
(error) ERR syntax error
127.0.0.1:6379> set key1 hello,world!  #逗号是可以的
OK
  1. 自增、自减操作
127.0.0.1:6379> set num 0  #插入一个初始值为0的数据
OK
127.0.0.1:6379> get num
"0"
127.0.0.1:6379> incr num  #指定key为‘num’的数据自增1,返回结果  相当于java中 i++
(integer) 1
127.0.0.1:6379> get num  #一般用来做文章浏览量、点赞数、收藏数等功能
"1"
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
127.0.0.1:6379> get num
"3"
127.0.0.1:6379> decr num  #指定key为‘num’的数据自减1,返回结果  相当于java中 i--
(integer) 2
127.0.0.1:6379> decr num
(integer) 1
127.0.0.1:6379> decr num
(integer) 0
127.0.0.1:6379> decr num  #可以一直减为负数~
(integer) -1
127.0.0.1:6379> decr num  #一般用来做文章取消点赞、取消收藏等功能
(integer) -2
127.0.0.1:6379> decr num
(integer) -3
127.0.0.1:6379> INCRBY num 10  #后面跟上by  指定key为‘num’的数据自增‘参数(10)’,返回结果
(integer) 7
127.0.0.1:6379> INCRBY num 10
(integer) 17
127.0.0.1:6379> DECRBY num 3  #后面跟上by  指定key为‘num’的数据自减‘参数(3)’,返回结果
(integer) 14
127.0.0.1:6379> DECRBY num 3
(integer) 11
  1. 截取、替换字符串操作
#截取
127.0.0.1:6379> set key1 "hello world!"
OK
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> GETRANGE key1 0 4  #截取字符串,相当于java中的subString,下标从0开始,不会改变原有数据
"hello"
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> GETRANGE key1 0 -1  #0-1相当于 get key1,效果一致,获取整条数据
"hello world!"
#替换
127.0.0.1:6379> set key2 "hello,,,world!"
OK
127.0.0.1:6379> get key2
"hello,,,world!"
127.0.0.1:6379> SETRANGE key2 5 888  #此语句跟java中replace有点类似,下标也是从0开始,但是有区别:java中是指定替换字符,Redis中是从指定位置开始替换,替换的数据根据你所需替换的长度一致,返回值是替换后的长度
(integer) 14
127.0.0.1:6379> get key2
"hello888world!"
127.0.0.1:6379> SETRANGE key2 5 67  #该处只替换了两位
(integer) 14
127.0.0.1:6379> get key2
"hello678world!"
  1. 设置过期时间、不存在设置操作
#设置过期时间,跟Expire的区别是前者设置已存在的key的过期时间,而setex是在创建的时候设置过期时间
127.0.0.1:6379> setex name1 15  dingdada  #新建一个key为‘name1’,值为‘dingdada’,过期时间为15秒的字符串数据
OK
127.0.0.1:6379> ttl name1  #查看key为‘name1’的key的过期时间
(integer) 6
127.0.0.1:6379> ttl name1
(integer) 5
127.0.0.1:6379> ttl name1
(integer) 3
127.0.0.1:6379> ttl name1
(integer) 1
127.0.0.1:6379> ttl name1
(integer) 0
127.0.0.1:6379> ttl name1  #返回为-2时证明该key已过期,即不存在
(integer) -2
#不存在设置
127.0.0.1:6379> setnx name2 dingdada2  #如果key为‘name2’不存在,新增数据,返回值1证明成功
(integer) 1
127.0.0.1:6379> get name2
"dingdada2"
127.0.0.1:6379> keys *
1) "name2"
127.0.0.1:6379> setnx name2 "dingdada3"  #如果key为‘name2’的已存在,设置失败,返回值0,也就是说这个跟set的区别是:set会替换原有的值,而setnx不会,存在即不设置,确保了数据误操作~
(integer) 0
127.0.0.1:6379> get name2
"dingdada2"
  1. mset、mget操作
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  #插入多条数据
OK
127.0.0.1:6379> keys *  #查询所有数据
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3  #查询key为‘k1’,‘k2’,‘k3’的数据
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> MSETNX k1 v1 k4 v4  #msetnx是一个原子性的操作,在一定程度上保证了事务!要么都成功,要么都失败!相当于if中的条件&&(与)
(integer) 0
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> MSETNX k5 v5 k4 v4  #全部成功
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k4"
3) "k3"
4) "k5"
5) "k1"
  1. 添加获取对象、getset操作
#这里其实本质上还是字符串,但是我们讲其key巧妙的设计了一下。
##mset student:1:name  student 相当于类名,1 相当于id,name 相当于属性
#如果所需数据全部这样设计,那么我们在java的业务代码中,就不需要关注太多的key
#只需要找到student类,下面哪个id,需要哪个属性即可,减少了代码的繁琐,在一定程度上可以理解为这个一个类的对象!
127.0.0.1:6379> mset student:1:name dingdada student:1:age 22  #新增一个key为‘student:1:name’,value为‘dingdada ’。。等数据
OK
127.0.0.1:6379> keys *  #查看所有的key
1) "student:1:age"
2) "student:1:name"
127.0.0.1:6379> mget student:1:age student:1:name  #获取数据
1) "22"
2) "dingdada"

##getset操作
127.0.0.1:6379> getset name1 dingdada1  #先get再set,先获取key,如果没有,set值进去,返回的是get的值
(nil)
127.0.0.1:6379> get name1
"dingdada1"
127.0.0.1:6379> getset name1 dingdada2  ##先获取key,如果有,set(替换)最新的值进去,返回的是get的值
"dingdada1"
127.0.0.1:6379> get name1  #替换成功
"dingdada2"

list(列表)
实际上是一个链表,before Node after , left,right 都可以插入值
如果key 不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表,也代表不存在!
在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点~
消息排队!消息队列 (Lpush Rpop), 栈( Lpush Lpop)

  1. lpush(左插入)、lrange(查询集合)、rpush(右插入)操作
#lpush
127.0.0.1:6379> lpush list v1  #新增一个集合
(integer) 1
127.0.0.1:6379> lpush list v2
(integer) 2
127.0.0.1:6379> lpush list v3
(integer) 3
#lrange
127.0.0.1:6379> LRANGE list 0 -1  #查询list的所有元素值
1) "v3"
2) "v2"
3) "v1"
127.0.0.1:6379> lpush list1 v1 v2 v3 v4 v5  #批量添加集合元素
(integer) 5
127.0.0.1:6379> LRANGE list1 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
###这里大家有没有注意到,先进去的会到后面,也就是我们的lpush的意思是左插入,l--left
#rpush
127.0.0.1:6379> LRANGE list 0 1  #指定查询列表中的元素,从下标零开始,1结束,两个元素
1) "v3"
2) "v2"
127.0.0.1:6379> LRANGE list 0 0  #指定查询列表中的唯一元素
1) "v3"
127.0.0.1:6379> rpush list rv0  #右插入,跟lpush相反,这里添加进去元素是在尾部!
(integer) 4
127.0.0.1:6379> lrange list 0 -1  #查看集合所有元素
1) "v3"
2) "v2"
3) "v1"
4) "rv0"
##联想:这里我们是不是可以做一个,保存的记录值(如:账号密码的记录),
每次都使用lpush,老的数据永远在后面,我们每次获取 0 0 位置的元素,是不是相当于更新了
数据操作,但是数据记录还在?想要查询记录即可获取集合所有元素!
  1. lpop(左移除)、rpop(右移除)操作
#lpop
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
127.0.0.1:6379> lpop list  #从头部开始移除第一个元素
"v5"
##################
#rpop
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> rpop list
"v1"
127.0.0.1:6379> LRANGE list 0 -1  #从尾部开始移除第一个元素
1) "v4"
2) "v3"
3) "v2"
  1. lindex(查询指定下标元素)、llen(获取集合长度) 操作
#lindex
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
127.0.0.1:6379> lindex list 1  #获取指定下标位置集合的元素,下标从0开始计数
"v3"
127.0.0.1:6379> lindex list 0  #相当于java中的indexof
"v4"
#llen
127.0.0.1:6379> llen list  #获取指定集合的元素长度,相当于java中的length或者size
(integer) 3
  1. lrem(根据value移除指定的值)
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
127.0.0.1:6379> lrem list 1 v2  #移除集合list中的元素是v2的元素1(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
127.0.0.1:6379> lrem list 0 v3 #移除集合list中的元素是v2的元素1,这里的01效果是一致的
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
127.0.0.1:6379> lpush list  v3 v2 v2 v2
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "v2"
2) "v2"
3) "v2"
4) "v3"
5) "v4"
127.0.0.1:6379> lrem list 3 v2  #移除集合list中元素为v2 的‘3’个,这里的参数数量,如果实际中集合元素数量不达标,不会报错,全部移除后返回成功移除后的数量值
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "v3"
2) "v4"
  1. ltrim(截取元素)、rpoplpush(移除指定集合中最后一个元素到一个新的集合中)操作
#ltrim
127.0.0.1:6379> lpush list v1 v2 v3 v4
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> ltrim list 1 2  #通过下标截取指定的长度,这个list已经被改变了,只剩下我们所指定截取后的元素
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "v3"
2) "v2"
################
#rpoplpush
127.0.0.1:6379> lpush list v1 v2 v3 v4 v5
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
127.0.0.1:6379> rpoplpush list newlist  #移除list集合中的最后一个元素到新的集合newlist中,返回值是移除的最后一个元素值
"v1"
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
127.0.0.1:6379> LRANGE newlist 0 -1  #确实存在该newlist集合并且有刚刚移除的元素,证明成功
1) "v1"
  1. lset(更新)、linsert操作
#lset
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
127.0.0.1:6379> 
127.0.0.1:6379> lset list 1 newV5  #更新list集合中下标为‘1’的元素为‘newV5’
OK
127.0.0.1:6379> LRANGE list 0 -1  #查看证明更新成功
1) "v5"
2) "newV5"
3) "v3"
4) "v2"
##注意点:
127.0.0.1:6379> lset list1 0 vvvv  #如果指定的‘集合’不存在,报错
(error) ERR no such key
127.0.0.1:6379> lset list 8 vvv  #如果集合存在,但是指定的‘下标’不存在,报错
(error) ERR index out of range
########################
#linsert
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "v3"
4) "v2"
127.0.0.1:6379> LINSERT list after v3 insertv3  #在集合中的‘v3’元素 ‘(after)之后’ 加上一个元素
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "v3"
4) "insertv3"
5) "v2"
127.0.0.1:6379> LINSERT list before v3 insertv3  #在集合中的‘v3’元素 ‘(before)之前’ 加上一个元素
(integer) 6
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "insertv3"
4) "v3"
5) "insertv3"
6) "v2"

Set(集合)元素唯一不重复、

需求:可实现共同好友、共同关注等需求

  1. sadd(添加)、smembers(查看所有元素)、sismember(判断是否存在)、scard(查看长度)、srem(移除指定元素)操作
#set中所有的元素都是唯一的不重复的!
127.0.0.1:6379> sadd set1 ding da mian tiao  #添加set集合(可批量可单个,写法一致,不再赘述)
(integer) 4
127.0.0.1:6379> SMEMBERS set1  #查看set中所有元素
1) "mian"
2) "da"
3) "tiao"
4) "ding"
127.0.0.1:6379> SISMEMBER set1 da  #判断某个值在不在set中,在返回1
(integer) 1
127.0.0.1:6379> SISMEMBER set1 da1  #不在返回0
(integer) 0
127.0.0.1:6379> SCARD set1  #查看集合的长度,相当于size、length
(integer) 4
127.0.0.1:6379> srem set1 da  #移除set中指定的元素
(integer) 1
127.0.0.1:6379> SMEMBERS set1  #移除成功
1) "mian"
2) "tiao"
3) "ding"
  1. srandmember(抽随机)操作
127.0.0.1:6379> sadd myset 1 2 3 4 5 6 7  #在set中添加7个元素
(integer) 7
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
127.0.0.1:6379> SRANDMEMBER myset 1  #随机抽取myset中1个元素返回
1) "4"
127.0.0.1:6379> SRANDMEMBER myset 1  #随机抽取myset中1个元素返回
1) "1"
127.0.0.1:6379> SRANDMEMBER myset 1  #随机抽取myset中1个元素返回
1) "5"
127.0.0.1:6379> SRANDMEMBER myset  #不填后参数,默认抽1个值,但是下面返回不会带序号值
"3"
127.0.0.1:6379> SRANDMEMBER myset 3  #随机抽取myset中3个元素返回
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> SRANDMEMBER myset 3  #随机抽取myset中3个元素返回
1) "6"
2) "3"
3) "5"
  1. spop(随机删除元素)、smove(移动指定元素到新的集合中)操作
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
127.0.0.1:6379> spop myset  #随机删除1个元素,不指定参数值即删除1"2"
127.0.0.1:6379> spop myset 1  #随机删除1个元素
1) "7"
127.0.0.1:6379> spop myset 2  #随机删除2个元素
1) "3"
2) "5"
127.0.0.1:6379> SMEMBERS myset  #查询删除后的结果
1) "1"
2) "4"
3) "6"
127.0.0.1:6379> smove myset myset2 1  #移动指定set中的指定元素到新的set中
(integer) 1
127.0.0.1:6379> SMEMBERS myset  #查询原来的set集合
1) "4"
2) "6"
127.0.0.1:6379> SMEMBERS myset2  #查询新的set集合,如果新的set存在,即往后加,如果不存在,则自动创建set并且加入进去
1) "1"
  1. sdiff(差集)、sinter(交集)、sunion(并集)操作
127.0.0.1:6379> sadd myset1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd myset2 3 4 5 6 7
(integer) 5
127.0.0.1:6379> SMEMBERS myset1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> SMEMBERS myset2
1) "3"
2) "4"
3) "5"
4) "6"
5) "7"
127.0.0.1:6379> SDIFF myset1 myset2  #查询指定的set之间的差集,可以是多个set
1) "1"
2) "2"
127.0.0.1:6379> SINTER myset1 myset2  #查询指定的set之间的交集,可以是多个set
1) "3"
2) "4"
3) "5"
127.0.0.1:6379> sunion myset1 myset2  #查询指定的set之间的并集,可以是多个set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"

Hash(哈希)

比String更加适合存对象

  1. hset(添加hash)、hget(查询)、hgetall(查询所有)、hdel(删除hash中指定的值)、hlen(获取hash的长度)、hexists(判断key是否存在)操作
127.0.0.1:6379> hset myhash name dingdada age 23  #添加hash,可多个
(integer) 2
127.0.0.1:6379> hget myhash name  #获取hash中key是name的值
"dingdada"
127.0.0.1:6379> hget myhash age  #获取hash中key是age的值
"23"
127.0.0.1:6379> hgetall myhash  #获取hash中所有的值,包含key
1) "name"
2) "dingdada"
3) "age"
4) "23"
127.0.0.1:6379> hset myhash del test  #添加
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "23"
5) "del"
6) "test"
127.0.0.1:6379> hdel myhash del age  #删除指定hash中的key(可多个),key删除后对应的value也会被删除
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
127.0.0.1:6379> hlen myhash  #获取指定hash的长度,相当于length、size
(integer) 1
127.0.0.1:6379> HEXISTS myhash name  #判断key是否存在于指定的hash,存在返回1
(integer) 1
127.0.0.1:6379> HEXISTS myhash age  #判断key是否存在于指定的hash,不存在返回0
(integer) 0
  1. hkeys(获取所有key)、hvals(获取所有value)、hincrby(给值加增量)、hsetnx(存在不添加)操作
127.0.0.1:6379> hset myhash age 23 high 173
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "23"
5) "high"
6) "173"
127.0.0.1:6379> hkeys myhash  #获取指定hash中的所有key
1) "name"
2) "age"
3) "high"
127.0.0.1:6379> hvals myhash   #获取指定hash中的所有value
1) "dingdada"
2) "23"
3) "173"
127.0.0.1:6379> hincrby myhash age 2  #让hash中age的value指定+2(自增)
(integer) 25
127.0.0.1:6379> hincrby myhash age -1  #让hash中age的value指定-1(自减)
(integer) 24
127.0.0.1:6379> hsetnx myhash nokey novalue  #添加不存在就新增返回新增成功的数量(只能单个增加哦)
(integer) 1 
127.0.0.1:6379> hsetnx myhash name miaotiao  #添加存在则失败返回0
(integer) 0
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "24"
5) "high"
6) "173"
7) "nokey"
8) "novalue"

zSet(有序集合)

需求: 成绩表排序,工资表排序,年龄排序等需求可以用zset来实现

  1. zadd(添加)、zrange(查询)、zrangebyscore(排序小-大)、zrevrange(排序大-小)、zrangebyscore withscores(查询所有值包含key)操作
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three  #添加zset值,可多个
(integer) 3
127.0.0.1:6379> ZRANGE myzset 0 -1  #查询所有的值
1) "one"
2) "two"
3) "three"
#-inf 负无穷  +inf 正无穷
127.0.0.1:6379> ZRANGEBYSCORE myzset -inf +inf  #将zset的值根据key来从小到大排序并输出
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> ZRANGEBYSCORE myzset 0 1  #只查询key<=1的值并且排序从小到大
1) "one"
127.0.0.1:6379> ZREVRANGE myzset 1 -1  #从大到小排序输出
1) "two"
2) "one"
127.0.0.1:6379> ZRANGEBYSCORE myzset -inf +inf withscores  #查询指定zset的所有值,包含序号的值
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
  1. zrem(移除元素)、zcard(查看元素个数)、zcount(查询指定区间内的元素个数)操作
127.0.0.1:6379> zadd myset 1 v1 2 v2 3 v3 4 v4
(integer) 4
127.0.0.1:6379> ZRANGE myset 0 -1
1) "v1"
2) "v2"
3) "v3"
4) "v4"
127.0.0.1:6379> zrem myset v3  #移除指定的元素,可多个
(integer) 1
127.0.0.1:6379> ZRANGE myset 0 -1
1) "v1"
2) "v2"
3) "v4"
127.0.0.1:6379> zcard myset  #查看zset的元素个数,相当于长度,size。
(integer) 3
127.0.0.1:6379> zcount myset 0 100  #查询指定区间内的元素个数
(integer) 3
127.0.0.1:6379> zcount myset 0 2  #查询指定区间内的元素个数
(integer) 2

Geospatial: 地理位置
城市经纬度查询: 经纬度查询
注意点1:两极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
注意点2:有效的经度从-180度到180度。
注意点3:有效的纬度从-85.05112878度到85.05112878度。
注意点4:m 为米。km 为千米。mi 为英里。ft 为英尺。

需求:实际需求中,我们可以用来查询附近的人、计算两人之间的距离等。当然,那些所需的经纬度我们肯定要结合java代码来一次导入,手动查询和录入太过于浪费时间!

  1. geoadd(添加)、geopos(查看)、geodist(计算距离)操作
127.0.0.1:6379> geoadd city 118.8921 31.32751 nanjing 197.30794 31.79322  
#当经纬度其中一个或者两个超过界限值,报错,信息如下:
(error) ERR syntax error. Try GEOADD key [x1] [y1] [name1] [x2] [y2] [name2] ...
#添加城市经纬度 语法格式: geoadd key 经度 纬度 name +++可多个添加
#添加成功后返回添加成功的数量值
127.0.0.1:6379> geoadd city 118.8921 31.32751 nanjing 117.30794 31.79322 hefei 102.82147 24.88554 kunming 91.13775 29.65262 lasa 116.23128 40.22077 beijing 106.54041 29.40268 chongqing  
(integer) 6
127.0.0.1:6379> ZRANGE city 0 -1  #注意:geo的查看方式和zset的命令是一致的,
#由此可知,geo本质上还是个集合,不过Redis官方对其进行了二次封装
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
127.0.0.1:6379> geopos city nanjing  #查看看指定城市的经纬度信息
1) 1) "118.89209836721420288"
   2) "31.32750976275760735"
127.0.0.1:6379> geopos city nanjing beijing  #查看看多个城市的经纬度信息
1) 1) "118.89209836721420288"
   2) "31.32750976275760735"
2) 1) "116.23128265142440796"
   2) "40.22076905438526495"
127.0.0.1:6379> geodist city nanjing beijing   #计算南京到北京之间的距离,默认返回单位是m
"1017743.1413"
127.0.0.1:6379> geodist city nanjing beijing km  #km  千米
"1017.7431"
127.0.0.1:6379> geodist city nanjing beijing mi  #mi  英里
"632.3978"
127.0.0.1:6379> geodist city nanjing beijing ft  #ft  英尺
"3339052.3010"
  1. georadius(查询附近位置)操作
127.0.0.1:6379> ZRANGE city 0 -1  #查看城市
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
#查看指定位置的1000公里范围内有哪些城市
127.0.0.1:6379> georadius city 120 38 1000 km  
1) "beijing"
2) "hefei"
3) "nanjing"
127.0.0.1:6379> georadius city 120 38 400 km  #查看指定位置的400公里范围内有哪些城市
(empty array)
127.0.0.1:6379> georadius city 120 38 550 km  #查看指定位置的550公里范围内有哪些城市
1) "beijing"
#查看指定位置的550公里范围内有哪些城市,withcoord指定返回城市的name
127.0.0.1:6379> georadius city 120 38 1000 km withcoord
1) 1) "beijing"
   2) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) 1) "118.89209836721420288"
      2) "31.32750976275760735"
#查看指定位置的550公里范围内有哪些城市,withdist指定返回城市的’经纬度‘值
127.0.0.1:6379> georadius city 120 38 1000 km withcoord withdist
1) 1) "beijing"
   2) "408.3496"
   3) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "732.6371"
   3) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) "749.0265"
   3) 1) "118.89209836721420288"
      2) "31.32750976275760735"
#查看指定位置的550公里范围内有哪些城市,withhash指定返回城市的’经纬度‘的hash值
#如果两个城市的hash值越’像‘,证明城市距离越近!
127.0.0.1:6379> georadius city 120 38 1000 km withcoord withdist withhash
1) 1) "beijing"
   2) "408.3496"
   3) (integer) 4069896088584598
   4) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "732.6371"
   3) (integer) 4052763834193093
   4) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) "749.0265"
   3) (integer) 4054278565840695
   4) 1) "118.89209836721420288"
      2) "31.32750976275760735"
#查看指定位置的550公里范围内有哪些城市,count num 指定返回’num‘个城市数据量
127.0.0.1:6379> georadius city 120 38 1000 km withcoord withdist withhash count 2
1) 1) "beijing"
   2) "408.3496"
   3) (integer) 4069896088584598
   4) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "732.6371"
   3) (integer) 4052763834193093
   4) 1) "117.30793744325637817"
      2) "31.79321915080526395"
  1. georadiusbymember (查找指定元素指定范围内的元素)、geohash (返回经纬度的hash值)、zrange、zrem(使用zset命令操作geo)
#查询南京 500公里范围有哪些城市
127.0.0.1:6379> georadiusbymember city nanjing 500 km
1) "hefei"
2) "nanjing"
#查询重庆 1500公里范围有哪些城市
127.0.0.1:6379> georadiusbymember city chongqing 1500 km
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
#返回北京和南京的经纬度的 hash值
127.0.0.1:6379> geohash city beijing nanjing
1) "wx4sucvncn0"
2) "wtsd1qyxfx0"
#查看所有城市name
127.0.0.1:6379> ZRANGE city 0 -1
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
#根据geo中的name删除g元素
127.0.0.1:6379> ZREM city lasa
(integer) 1
#删除成功
127.0.0.1:6379> ZRANGE city 0 -1
1) "kunming"
2) "chongqing"
3) "hefei"
4) "nanjing"
5) "beijing"

Hyperloglog: 基数
首先得明白什么是基数?
再数学层面上可以说是:两个数据集中不重复的元素~
但是再Redis中,可能会有一定的误差性。 官方给出的误差率是0.81%。
Hyperloglog的优点: 占用的内存是固定的,2^64个元素,相当于只需要12kb的内存即可。效率极高!

需求:如果在实际业务中,允许一定的误差值,我们可以使用基数统计来计算~效率非常高!比如:网站的访问量,就可以利用Hyperloglog来进行计算统计!

  1. pfadd(添加数据集)、pfcount(统计数据集)、pfmegre(合并数据集-自动去重)
127.0.0.1:6379> pfadd dataList 1 2 3 4 5 6 7  #添加数据集
(integer) 1
127.0.0.1:6379> pfcount dataList  #统计数据集中的元素
(integer) 7
127.0.0.1:6379> pfadd dataList1 4 5 6 7 8 9 10  #添加数据集
(integer) 1
127.0.0.1:6379> pfcount dataList1  #统计数据集中的元素
(integer) 7
#将dataList 和dataList1  两个数据集合并成一个新的 newdata数据集,并且自动去重
127.0.0.1:6379> pfmerge newdata dataList dataList1  
OK
127.0.0.1:6379> pfcount newdata
(integer) 10

Bitmap: 位存储
Bitmap 位图,数据结构! 都是操作二进制位来进行记录,就只有0 和 1 两个状态!

需求:实际需求中,可能需要我们统计用户的登陆信息,员工的打卡信息等等。只要是事务的只有两个状态的,我们都可以用Bitmap来进行操作

  1. setbit(添加)、getbit(获取)、bitcount(统计)操作
127.0.0.1:6379> setbit login 1 1   #添加周一已登陆 为1
(integer) 0
127.0.0.1:6379> setbit login 2 1
(integer) 0
127.0.0.1:6379> setbit login 3 1
(integer) 0
127.0.0.1:6379> setbit login 4 0  #添加周四未登陆 为0
(integer) 0
127.0.0.1:6379> setbit login 5 0
(integer) 0
127.0.0.1:6379> setbit login 6 1
(integer) 0
127.0.0.1:6379> setbit login 7 0
(integer) 0
127.0.0.1:6379> getbit login 1  #获取周一是否登录
(integer) 1
127.0.0.1:6379> getbit login 4  #获取周四是否登陆
(integer) 0
127.0.0.1:6379> bitcount login  #统计这周登陆的天数
(integer) 4

redis的事务和锁
Redis是支持单条命令事务的,但是事务并不能保证原子性

  • 事务
    ①原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
    ②一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
    ③隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
    ④持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
  • 乐观锁
    ①当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的。
    ②没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。只有更新数据的时候去判断一下,在此期间是否有人修改过被监视的这个数据,没有的话正常执行事务,反之执行失败
  • 悲观锁
    什么时候都会出问题,所以一直监视着,没有执行当前步骤完成前,不让任何线程执行,十分浪费性能,一般不使用

在Redis事务没有没有隔离级别的概念
在Redis单条命令式保证原子性的,但是事务不保证原子性
在Redis是可以实现乐观锁的

  1. 正常执行事务
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 26  #添加数据
QUEUED
127.0.0.1:6379> set high 172  #添加数据
QUEUED
127.0.0.1:6379> exec  执行事务
1) OK
2) OK
3) OK
127.0.0.1:6379> get name  #获取数据成功,证明事务执行成功
"dingyongjun"
127.0.0.1:6379> get age
"26"
  1. 放弃事务
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 26  #添加数据
QUEUED
127.0.0.1:6379> discard  #放弃事务
OK
127.0.0.1:6379> get name  #不会执行事务里面的添加操作
(nil)
  1. 编译时异常,代码有问题,或者命令有问题,所有的命令都不会被执行
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 23  #添加数据
QUEUED
127.0.0.1:6379> getset name  #输入一个错误的命令,这时候已经报错了,但是这个还是进入了事务的队列当中
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set high 173  #添加数据
QUEUED
127.0.0.1:6379> exec  #执行事务,报错,并且所有的命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name  #获取数据为空,证明没有执行
(nil)
  1. 运行时异常,除了语法错误不会被执行且抛出异常后,其他的正确命令可以正常执行
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加字符串数据
QUEUED
127.0.0.1:6379> incr name  #对字符串数据进行自增操作
QUEUED
127.0.0.1:6379> set age 23  #添加数据
QUEUED
127.0.0.1:6379> get age  #获取数据
QUEUED 
127.0.0.1:6379> exec  #执行事务。虽然对字符串数据进行自增操作报错了,但是其他的命令还是可以正常执行的
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "23"
127.0.0.1:6379> get age  #获取数据成功
"23"

乐观锁

  1. watch(监视)
127.0.0.1:6379> set money 100  #添加金钱100
OK
127.0.0.1:6379> set cost 0  #添加花费0
OK
127.0.0.1:6379> watch money  #监控金钱
OK
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> DECRBY money 30  #金钱-30
QUEUED
127.0.0.1:6379> incrby cost 30  #花费+30
QUEUED
127.0.0.1:6379> exec  #执行事务,成功!这时候数据没有发生变动才可以成功
1) (integer) 70
2) (integer) 30
  1. 多线程测试watch
#线程1
127.0.0.1:6379> set money 100  #添加金钱100
OK
127.0.0.1:6379> set cost 0  #添加花费0
OK
127.0.0.1:6379> watch money  #开启监视(乐观锁)
OK 
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> DECRBY money 20  #金钱-20
QUEUED
127.0.0.1:6379> INCRBY cost 20   #花费+20
QUEUED
#这里先不要执行,先执行线程2来修改被监视的值
127.0.0.1:6379> exec  #执行报错,因为我们监视了money这个值,如果事务要对这个值进行操作前
#监视器会判断这个值是否正常,如果发生改变,事务执行失败!
(nil)
#线程2,这个在事务执行前操作执行
127.0.0.1:6379> INCRBY money 20  #金钱+20
(integer) 120

文章来源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值