Redis常用命令
redis中不区分大小写命令
五大数据类型
Redis-Key
- keys * :查看所有的key
- set key value :设置key并且存入value值
- get key :获得key的value值
- exists key :判断当前key是否存在
- del key :移除key
- expire key 秒数 :设置key的过期时间
- ttl key :查看当前key剩余时间
- type key :查看当前key中value是什么类型
String(字符串类型)
- append key “追加内容” :向指定key中的value字符串追加内容,如果当前key不存在就相当于set key
- strlen key :查看当前key中value字符串的长度
- set views(可自主命名)0 :设置初始浏览量为0
- incr views :自增1 浏览量变为1
- decr views :自减1 浏览量变为-1
- incrby views 数字 :可以自己来决定增加多少
- decrby views 数字 :可以自己来决定减少多少
- getrange key 起始位置(数字) 结尾位置(数字) :截取字符串 如果为0 -1,则表示获取全部的字符串,和get key是一样的
- setrange key 起始位置(数字) 替换字符串 :替换指定位置开始的字符串
- setex(set with expire) : 设置过期时间
- setnx(set if not exists):不存在,再设置(在分布式锁中会常常使用)
- setex key1 30 “hi”:设置key1的值为hi,30秒后过期
- setnx key1 ‘‘hello’’ : 如果key1不存在,则创建key1。如果key存在,则创建失败!
- mset key1 value1 key2 value2… : 同时设置多个值
- mget key1 key2… : 同时获取多个值
- msetnx key1 value1 key2 value2… : 同时设置多个值,如果key1或者key2任意一个已经存在,则创建失败。这是一个原子性的的操作,要么一起成功,要么一起失败!
- set user:1 {name : zhangsan , age : 3} : 设置一个user:1对象,值为json字符保存一个对象
- 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在Redis中是完全OK的,可以实现复用
- mset user:1:name zhangsan user:1:age 2
- mget user:1:name user:1:age
- getset key value : 先get然后再set。如果不存在值,则返回nil。如果存在值,获取原来的值,并设置新的值。
String类似的使用场景:value除了是字符串还可以是数字。
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
List
有序可重复列集合
在redis里面,可以将list玩成队列,栈,阻塞队列
- 两边一边进,一边出 队列
- 只能一边进,一边不能出(先进后出)栈
- 可以从两边出 阻塞队列
所有的list命令都是用l开头的
- lpush list value1 value2 … : 将一个值或多个值,插入到列表头部(从左往右放入)
- rpush list value1 value2… : 将一个值或多个值,插入到列表尾部(从右往左放入)
- lrange list num1 num2 : 通过区间获取具体的值 如果值为0 -1,则获取list中所有的值
- lpop list :移除list的第一个元素
- rpop list :移除list的最后一个元素
- exists list : 判断这个列表是否存在
- lindex list num : 通过下标获得list中的某一个值
- llen list :返回list列表的长度
- lrem list count value : 移除list集合中指定个数的value,精确匹配 如果count>0,从头往尾移除值为value的元素。如果conut<0,从尾往头移除值为value的元素
- ltrim list start stop : 通过下标截取指定的长度, 此时这个list已经被改变了,截断了只剩下截取的元素
- rpoplpush oldList newList : 移出列表的最后一个元素,将它移动到新的列表中
- lset list index value:将列表中指定下标的值替换为,另外一个值,更新操作 如果不存在列表,我们去更新就会报错。如果存在,更新当前下标的值。如果下标所在的位置没有值,也会报错
- linsert list before/after value insertValue : 将某个具体的value插入到列表中某个元素的前面或者后面 如果有两个相同的value,往下标靠前的那个value插入
list实际上是一个链表,before Node after, left,right都可以插入值
如果key不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表,也代表不存在
在两边插入或者改动值,效率最高!中间元素,相对来说效率发会低一点
list可用作于消息排队! 消息队列(lpush rpop),栈(lpush lpop)
Set
无序不重复集合,set中的值是不能重读的(即不能重复)
- sadd set member1 member2 … : set集合中添加元素
- smembers set : 查看指定set的所有值
- sismember set member : 判断某一个值是不是在set集合中
- scard set :获取set集合中的元素个数
- srem set member :移除set集合中的指定元素
- srandmember set : 从set集合中随机抽选出一个元素
- srandmember set count : 从set集合中随机抽选出指定个数元素
- spop set : 从set集合中随机删除一些元素
- smove set set2 member : 将一个指定的值,移动到另外一个set集合中
- sdiff set1 set2 : 查看set1集合相对于set2集合中没有的元素(差集)
- sinter set1 set2 : 查看两个集合中共同存在的元素(交集,可实现共同好友功能)
- sunion set1 set2 : 查看两个集合中所有的元素(并集)
共同关注,共同爱好,推荐好友
Hash(哈希)
Map集合,key-map!(kye-{key-value}) ,此时key的值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-value!
- hset key filed value : set一个具体 key-value
- hget key field : 获取一个字段值
- hmset key filed1 value1 filed2 value2 … : set多个 key-value
- hmget key filed1 filed2 : 获取多个字段值
- hgetall key : 获取全部的数据
- hdel key field : 删除hash指定key字段!对应的value值也就消失了
- hlen key : 读取hash表的字段数量
- hexists key field : 判断hash中指定字段是否存在
- hkeys key : 只获得所有的field
- hvals key : 只获得所有的value
- hset key field num : 指定增量
- hsetnx key field value :如果存在则可以设置,如果不存在则不可以设置
hash常用于存储变更的数据,user name age ,尤其是用户信息之类的,经常变动的信息!hash更适合于对象的存储,String更加适合字符串存储!
Zset(有序集合)
在set的基础上,增加了一个值。
set key1 value1 ==> zset key1 score value1
- zadd set score vaue : 添加一个值
- zadd set score1 value1 score 2 value2 … : 添加多个值
- zrange set start stop : 通过区间获取具体的值 如果值为0 -1,则获取Zset中所有的值
- zrangebyscore score -inf +inf : 显示全部的用户,并且按score从小到大排列(-inf +inf分别表示负无穷和正无穷,也可以根据自己需求自定义范围)
- zrangebyscore score -inf +inf withscores : 显示全部的用户,并且按score从小到大排列并且附带score
- zrevrangebyscore scoure +inf -inf : 显示全部的用户,并且按score从大到小排列
- zrem set value : 移除有序集合中的指定元素
- zcard set :获取有序集合中的个数
- zcount set min max : 获取指定区间的数量
Zset相对于set,增加了排序功能
存储班级成绩表,工资表排序
带权重进行判断 例如:普通消息为1 重要消息为2
排行榜应用实现
三种特殊数据类型
geospatial(地理位置)
朋友的定位,附近的人,打车距离计算?
Redis的Geo在redis3.2版本就推出了!这个功能可以推算出地理位置的信息,两地之间的距离,方圆几里的人。
getadd 添加地理位置
规则:两级无法添加,一般会通过下载城市数据通过Java程序一次性导入
有效的经度从-180度到180度
有效的纬度从-85.05112878到85.05112878
当坐标位置超出上述指定范围时,该命令会返回一个错误
(error) ERR invalid longitude,latitude pair 39.900000,116.400000
- geoadd key longitude(经度) latitude(纬度) member(名称) :添加一个地理位置
- geoadd key longitude1 latitude1member1 longitude2 latitude2 member2 : 添加多个地理位置
getpos :获得当前定位,一定是一个坐标值
- geopos key member : 获取指定的城市的经度和纬度
geodist : 可以计算两个地方的直线距离
单位:
m : 表示单位为米
km : 表示单位为千米
mi : 表示单位为英里
ft : 表示单位为英尺
- geodist key member1 member2 unit(单位) : 计算城市member1和城市member2之间的直线距离
georadius 以给定的经纬度为中心,找出某一半径内的元素
附近的人 (获得所有附近的人的地址,定位!)通过半径来查询
所有数据都应该录入key中,才会让结果更加清晰
georadius key longitude(经度) latitude(纬度) radius(半径) unit(单位)
withdist 显示到中间距离的位置
withcoord 显示他人的定位信息
count num 筛选出指定的结果,显示几个城市
- georadius key longitude latitude radius(半径) unit(单位) :获取以这个经纬度为中心,寻找方圆radius unit内的城市
georadiusbymember 找出位于指定元素周围的其他元素
- georadiusbymember key member radius(半径) unit(单位) : 获取以member城市为中心,方圆radius unit内的城市
geohash 返回一个或多个位置元素的GeoHash表示
将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么表示距离越近
- geohash key member:返回11个字符的GeoHash字符串
geospatial底层实现原理其实就是Zset,可以使用Zset命令来操做geospatial 例如:查看,删除…
- zrange key 0 -1 : 查看地图中全部的元素
- zrem key member : 移除指定元素
hyperloglog(基数统计的算法)
什么是基数?基数是一个集合中不重复的元素
A{1,3,5,79} 基数(不重复的元素) = 5 ,可以接受误差!
简介:
Redis 2.8.9版本就更新了Hyperloglog数据结构
Redis Hyperloglog 基于统计的算法
优点:占用的内存是固定的,2*64不同的元素的技术,只需要12KB的内存,如果要从内存角度来比较的话Hyperloglog首选!
网页的UV(独立访客数,一个人访问一个网站多次,但是还是算作一个人)
传统的方式,set保存用户的id,然后就可以统计set中元素的数量作为标准判断
这个方式如果保存大量的用户id,就会比较麻烦。我们的目的是为了计数,而不是保存用户id
0.81%的错误率!统计UV任务,可以忽略不计!
- pfadd key element1 element2 … : 创建一组元素
- pfcount key : 统计key元素的基数数量
- pfmerge newKey oldKey1 oldKey2 … : 合并oldKey1 oldKey2 … =>newKey (并集)
如果允许容错,那么一定可以使用Hyperloglog!
如果不允许容错,就是用set或者自己的数据类型即可!
Bitmaps(位图)
位存储
统计用户信息,活跃,不活跃!登录,未登录!打卡!两个状态的,都可以使用Bitmaps
Bitmaps位图,数据结构!都是操作二进制来进行记录,就只有0和1两个状态!
例子:一年打卡365次=365bit 一字节=8bit 一年46个字节左右
- setbit key offset value :给位图指定索引设置值,返回该索引位置的原始值
- getbit key offset :获取位图指定索引的值
- bitcount key start end :获取位图指定范围(start到end,单位为字节,如果不指定就是获取全部)位值为1的个数
事务
Redis事物本质:一组命令的集合!一个事物中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性,顺序性,排他性!执行一系列的命令!
------ 队列 set set set 执行------
Redis事务没有隔离级别的概念!
所有的命令都在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!Exec
Redis单条命令式保持原子性,但是事务不保证原子性!
Redis的事务:
- 开启事务 multi
- 命令入队 …
- 执行事务 exec
编译型异常(代码有问题!命令有错!),事务中所有命令都不会被执行!
运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
监控 Watch 可实现乐观锁
悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会上锁
乐观锁:
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据
Redis Watch 监视测试
正常执行成功!
127.0.0.1:6379> set money 500 # 设置初始金额为500
OK
127.0.0.1:6379> set out 0 # 设置花费初始金额为0
OK
127.0.0.1:6379> watch money # 监视money对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379> decrby money 300 # 花费300,初始金额-300
QUEUED
127.0.0.1:6379> incrby out 300 # 花费初始金额+300
QUEUED
127.0.0.1:6379> exec
1) (integer) 200
2) (integer) 300
测试多线程修改值,使用watch可以当做redis的乐观锁操作!
127.0.0.1:6379> set money 500
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money # 监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 300
QUEUED
127.0.0.1:6379> incrby out 300
QUEUED
127.0.0.1:6379> exec # 执行之前,另外一个线程,修改了money的值,这个时候导致事务执行失败
(nil)
在开启一个redis服务,模拟多线程修改值
127.0.0.1:6379> get money
"500"
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379>
解决方法:
127.0.0.1:6379> unwatch #解锁 如果发现事务执行失败的,就先解锁
OK
127.0.0.1:6379> watch money # 获取最新的值,再次监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 300
QUEUED
127.0.0.1:6379> incrby out 300
QUEUED
127.0.0.1:6379> exec # 比对监视的值是否发生了变化,如果没有变化,那么可以执行成功,如果变化就执行失败
1) (integer) 700
2) (integer) 300
127.0.0.1:6379>