1.Redis
Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
2.redis安装
1.下载redis.tar.gz
2.make
3.make install PREFIX=/usr/local/redis
4.赋值配置文件 并且修改redi.config 将daemonize no 改成daemonize yes 使用redis.config后台启动redis.server
3. redis基础命令
redis有16个数据库默认使用第0个可以使用select 进行切换数据库
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize #查看db大小
(integer) 0
127.0.0.1:6379[3]> set name hdh #在三号数据库设置一个值
OK
127.0.0.1:6379[3]> dbsize #查看db大小
(integer) 1
127.0.0.1:6379[3]> set name hdh #在三号数据库设置一个值
OK
127.0.0.1:6379[3]> flushdb #清除当前数据库
OK
127.0.0.1:6379[3]> flushall #清除所有数据库
OK
redis 是单线程的
Redis是非常快的,Redis是基于内存操作,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据内存和网络带宽来决定的。
为什么Redis是单线程还是很快?
Redis是基于内存操作,Redis所有的数据都是存放在内存中的,多线程直接的切换都是每必要的耗时行为,对于内存来说单线程是最快的
127.0.0.1:6379[3]> set name hdh
OK
127.0.0.1:6379[3]> set age 18
OK
127.0.0.1:6379[3]> exists name #判断一个key是否存在
(integer) 1
127.0.0.1:6379[3]> exists name1
(integer) 0
127.0.0.1:6379[3]> move name 1 #移除第一个key为name的
(integer) 1
127.0.0.1:6379> set name hdh
OK
127.0.0.1:6379> get name
"hdh"
127.0.0.1:6379> expire name 10 #设置key的过期时间 单位秒
(integer) 1
127.0.0.1:6379> ttl name #查询Key剩余过期时间 -2已过期
(integer) 7
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> set name hdh
OK
127.0.0.1:6379> type name 判断key的类型
string
2.String类型
以下的所有的方法都会被转化为java操作的中的方法
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> get key
(nil)
127.0.0.1:6379> exists key1 #判断key是否存在
(integer) 1
127.0.0.1:6379> append key1 hello #向key追加一个值 key不存在创建
(integer) 7 #返回key的长度
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> strlen key1 #查询key的长度
(integer) 7
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #value值自增1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> decr views #value值减1
(integer) 0
127.0.0.1:6379> incrby views 10 #设置步长value值自增10
(integer) 10
127.0.0.1:6379> get views
"10"
127.0.0.1:6379> set key abcdefg
OK
127.0.0.1:6379> get key
"abcdefg"
127.0.0.1:6379> getrange key 0 3 #截取字符串 开始和结尾的下标
"abcd"
127.0.0.1:6379> getrange key 0 -1
"abcdefg"
127.0.0.1:6379> set key1 abcdefg
OK
127.0.0.1:6379> get key1
"abcdefg"
127.0.0.1:6379> setrange key1 1 x #替换下标为1的值
(integer) 7
127.0.0.1:6379> get key1
"axcdefg"
#setex (set with expire)#设置过期时间
#setnx (set if not exist) #不存在设置(在分布式锁中常常会用到)
127.0.0.1:6379> setex key3 30 abcd #设置key3的为abcd 30秒后过期
OK
127.0.0.1:6379> ttl key3 #查选key3 的过期时间 -1没有过期时间 -2 已经过期
(integer) 24
127.0.0.1:6379> get key3
"abcd"
127.0.0.1:6379> setnx mykey redis #判断mykey是不是存在 不存在创建返回 1 存在返回0
(integer) 1
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey java
(integer) 0
127.0.0.1:6379> mset k1 a k2 b k3 c
OK
127.0.0.1:6379> mget k1 k2 k3
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> msetnx k1 a k4 d #msetnx是原子操作
(integer) 0 #失败
#redis 对象用作key json用来存值
#巧妙地设计 user:{id}:{filed}
127.0.0.1:6379> mset user:1:name zhansan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhansan"
2) "2"
127.0.0.1:6379> getset #先get再set 如果存在值先get 不存在返回nul 。
3.List类型
redis中 list可以实现栈、堆、队列
list可以左边进值右边出值,可以完成消息队列(lpush,rpop), 先进先出
栈操作:(lpush,lpop)先进后出
127.0.0.1:6379> lpush list one #将一个或者多个值插入到列表的头部
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list whree
(integer) 3
127.0.0.1:6379> lrange list 0 -1 #获取list中的值(全部)
1) "whree"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 #获取list中的值(下标为0和1的)
1) "whree"
2) "two"
127.0.0.1:6379> rpush list right #向尾部追加一个或者多个值
(integer) 4
127.0.0.1:6379> lrange list 0 -1 #获取list中的值(全部)
1) "whree"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lrange list 0 -1
1) "whree"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list #移除头部的一个值
"whree"
127.0.0.1:6379> rpop list #移除尾部的一个值
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 0 #获取指定下标的值
"two"
127.0.0.1:6379>
############################################################
llen
127.0.0.1:6379> llen list #返回列表的长度
(integer) 3
127.0.0.1:6379> lrem list 1 a #移除list中指定个数的value 移除1个value是a的值
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
127.0.0.1:6379> RPUSH list key1 key2 key3 key4 #向list尾部插入值
(integer) 4
127.0.0.1:6379> ltrim list 1 2 #截取list 从下标1到2
OK
127.0.0.1:6379> lrange list 0 -1
1) "key2"
2) "key3"
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lset list 1 a #通过下标修改list中的值 修改list下标为1的值 如果不存在会报错
OK
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "a"
3) "3"
4) "4"
#linsert 将一个值插入到list中 一个值的后面
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "a"
3) "3"
4) "4"
127.0.0.1:6379> linsert list before 4 5 #向list值为4 的后面(前面)插入一个值为5数
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "a"
3) "3"
4) "5"
5) "4"
4.
127.0.0.1:6379> sadd name hdh #向set中存入一个或者多个元素
(integer) 1
127.0.0.1:6379> sadd name xj
(integer) 1
127.0.0.1:6379> sadd name dd
(integer) 1
127.0.0.1:6379> smembers name #查选set中所有的元素
1) "xj"
2) "dd"
3) "hdh"
127.0.0.1:6379> sismember name hdh #判断set中是否有某个元素
(integer) 1
127.0.0.1:6379> sadd set a
(integer) 1
127.0.0.1:6379> sadd set b
(integer) 1
127.0.0.1:6379> sadd set c
(integer) 1
127.0.0.1:6379> scard set #查询set中元素个数
(integer) 3
127.0.0.1:6379> srem set a #移除set中一个指定的元素
(integer) 1
127.0.0.1:6379> smembers set
1) "c"
2) "b"
127.0.0.1:6379> srandmember set #随机抽出一个元素
"c"
127.0.0.1:6379> srandmember set
"b"
127.0.0.1:6379> spop set #随机删除一个元素
"c"
127.0.0.1:6379> spop set
"b"
127.0.0.1:6379> sadd set a b c d e
(integer) 5
127.0.0.1:6379> smembers set
1) "d"
2) "c"
3) "a"
4) "b"
5) "e"
127.0.0.1:6379> smove set set1 f #将set集合中的f元素移动到set1集合中
(integer) 1
127.0.0.1:6379> smember set
1) "b"
2) "c"
3) "d"
4) "e"
127.0.0.1:6379> smembers set1
1) "a"
2) "f"
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2 #差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2 #交集
1) "c"
127.0.0.1:6379> sunion key1 key2 #并集
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
5.Hash(哈希)
Map集合,key-map-->key-<key-vle>!这时候vle就是一个Map1
hash变更数据:可以存放一个user
hset user:1 name hdh
hset user:1 age 24
127.0.0.1:6379> hset myhash filed hdh #set一个key-value
(integer) 1
127.0.0.1:6379> hget myhash filed
"hdh"
127.0.0.1:6379> hmset myhash filed xj filed1 hello #set多个key-value
OK
127.0.0.1:6379> hmget myhash filed filed1 #get一个或者多个key-value
1) "xj"
2) "hello"
127.0.0.1:6379> hgetall myhash #get全部的key-value
1) "filed"
2) "xj"
3) "filed1"
4) "hello"
127.0.0.1:6379> hdel myhash filed #删除指定的key
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "filed1"
2) "hello"
127.0.0.1:6379> hlen myhash #计算hash长度 有多少个key-map键值对
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> hexists myhash filed1 #判断hash中key是否存在
(integer) 1
127.0.0.1:6379> hexists myhash filed2
(integer) 0
127.0.0.1:6379> hkeys myhash #获取hash中的所有的key
1) "filed1"
127.0.0.1:6379> hvals myhash #获取hash中的所有的value
1) "hello"
127.0.0.1:6379> hset myhash age 10
(integer) 1
127.0.0.1:6379> hincrby myhash age 10 #hash自增10
(integer) 20
127.0.0.1:6379> hincrby myhash age -10 #hash自增-10
(integer) 10
127.0.0.1:6379> hsetnx myhash name hdh #如果不存在可以设置
(integer) 1
127.0.0.1:6379> hsetnx myhash name hdh#如果存在不可以设置
(integer) 0
6.Zset(有序集合)
在set的基础上,增加了一个值
set k1 v1
zset k1 score1 v1
127.0.0.1:6379> zadd myzset 1 one #向zset中添加一个值
(integer) 1
127.0.0.1:6379> zadd myzset 2 two 3 three #向zset中添加多个值
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1 #获取zet中所有的值
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zadd salary 1000 hdh
(integer) 1
127.0.0.1:6379> zadd salary 2000 xj
(integer) 1
127.0.0.1:6379> zadd salary 3000 zs
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf #按照salary正序排序-inf +inf 所有的
1) "hdh"
2) "xj"
3) "zs"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #按照salary升序排序带上value
1) "hdh"
2) "1000"
3) "xj"
4) "2000"
5) "zs"
6) "3000"
127.0.0.1:6379> zrange salary 0 -1 withscores #从大到小排序
1) "xj"
2) "2000"
3) "zs"
4) "3000"
127.0.0.1:6379>
127.0.0.1:6379> zrange salary 0 -1
1) "hdh"
2) "xj"
3) "zs"
127.0.0.1:6379> zrem salary hdh #移除一个元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "xj"
2) "zs"
127.0.0.1:6379> zcard salary #集合中元素的个数
(integer) 2
127.0.0.1:6379> zadd myzset 1 a 2 b 3 c
(integer) 3
127.0.0.1:6379> zcount myzset 1 3 #获取zset指定区间之间的元素数量
(integer) 3
127.0.0.1:6379> zcard myzset #获取zset的元素数量
(integer) 3
5.三种特殊的数据类型
1.geospatial
朋友圈定位,附近的人,打车的距离
GEOADD:
该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:
-
有效的经度从-180度到180度。
-
有效的纬度从-85.05112878度到85.05112878度。
当坐标位置超出上述指定范围时,该命令将会返回一个错误
(error) ERR invalid longitude,latitude pair 39.900000,116.400000#及维度超出范围
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijin #添加一个或者多个地理位置
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shengzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
127.0.0.1:6379> geopos china:city beijin #获取指定的城市的经纬度
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2.geodist
返回两个给定位置之间的距离。
如果两个位置之间的其中一个不存在, 那么命令返回空值。
指定单位的参数 unit 必须是以下单位的其中一个:
-
m 表示单位为米。
-
km 表示单位为千米。
-
mi 表示单位为英里。
-
ft 表示单位为英尺。
如果用户没有显式地指定单位参数, 那么 GEODIST
默认使用米作为单位。
GEODIST
127.0.0.1:6379> geodist china:city beijin shanghai km #北京到上海的距离
"1067.3788"
我附近的人?(获得我附近所有人的地址,定位)
127.0.0.1:6379> georadius china:city 110 30 1000 km #查找指定坐标 110 30 附近1000km的人
1) "chongqin"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 1000 km withdist #查找指定坐标 110 30 附近1000km的人 显示和你的距离
1) 1) "chongqin"
2) "341.9374" #和你的距离
2) 1) "xian"
2) "483.8340"
3) 1) "shengzhen"
2) "924.6408"
4) 1) "hangzhou"
2) "977.5143"
127.0.0.1:6379> GEORADIUS china:city 100 30 1000 km withdist withcoord count 1
##查找指定坐标 110 30 附近1000km的人并且显示 withcoord详细坐标 count取一个
1) 1) "chongqin"
2) "629.6756"
3) 1) "106.49999767541885376"
2) "29.52999957900659211"
通过指定的元素查找附近的人
127.0.0.1:6379> georadiusbymember china:city beijin 1000 km withdist withcoord
#找出指定元素(beijin)1000km之内的所有元素的详情
1) 1) "beijin"
2) "0.0000"
3) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "xian"
2) "910.0565"
3) 1) "108.96000176668167114"
2) "34.25999964418929977"
geohash 返回一个或者多个位置元素的经纬度 GeoHash表示
#将二维码的经纬度转换为一维的字符串,如果两个字符串越接近,那么距离越接近
127.0.0.1:6379> geohash china:city beijin chongqin
1) "wx4fbxxfke0"
2) "wm5xzrybty0
geo底层的实现原理是Zste!意味着我们可以使用Zset命令操作
127.0.0.1:6379> zrange china:city 0 -1 #查看地图中所有的元素
1) "chongqin"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijin"
127.0.0.1:6379> zrem china:city beijin #移除地图中指定的元素
(integer) 1
2.Hyperloglog 数据结构
什么是基数?
一个集合中不存在重复的元素,Hyperloglog存储的就是基数
网页的的访问数量(多次访问只算一次)
Hyperloglog 存放:2^64次方个不同的用户id,只需要12kb内存,但是存在0.81%的误差
传统方式 set方式保存用户id。数量级过大时非常消耗资源。而且我们需要的不是用户id,需要的事访问数量。
127.0.0.1:6379> pfadd key1 1 2 3 4 #创建一组数据结构
(integer) 1
127.0.0.1:6379> pfadd key2 3 4 5 6 #创建一组数据结构
(integer) 1
127.0.0.1:6379> pfmerge key3 key 1 key2 #合并两个数据结构
OK
127.0.0.1:6379> pfcount key3 #查询一组组数据结构的个数
(integer) 6
3.Bitmaps
位存储
统计活跃和不活跃用户,登录,不登陆的用户。只有2种状态的都可以使用Bitmap表示。
127.0.0.1:6379> setbit id+y+y 1 0 #设置 用户id+y+y 用户 哪一年 哪一月 哪一天是否登录
(integer) 0
127.0.0.1:6379> setbit id+y+y 2 0
(integer) 0
127.0.0.1:6379> getbit id+y+y 1 #获得 用户id+y+y 用户 哪一年 哪一月 哪一天是否登录
(integer) 0
127.0.0.1:6379> bitcount id+y+y 获得 用户id+y+y 当月的打卡次数
(integer) 2