八、三种特殊数据类型
8.1、geospatial 地理位置
Redis的Geo可以推算地理位置的信息
只有6个命令:
- geoadd:添加地理位置的坐标。
- geopos:获取地理位置的坐标。
- geodist:计算两个位置之间的距离。
- georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
- georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
- geohash:返回一个或多个位置对象的 geohash 值。
geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。
geoadd 语法格式如下:
GEOADD key latitude longitude member [latitude longitude member ...]
geoadd:添加地理位置的坐标。
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing
(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 113.28 23.12 guangzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 113.66 34.75 henan
(integer) 1
geopos:获取地理位置的坐标。
127.0.0.1:6379> GEOPOS china:city beijing # 获取指定城市的精度和纬度
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS china:city henan
1) 1) "113.65999907255172729"
2) "34.74999926510690784"
127.0.0.1:6379>
geodist:计算两个位置之间的距离。
geodist 用于返回两个给定位置之间的距离。
geodist 语法格式如下:
GEODIST key member1 member2 [m|km|ft|mi]
member1 member2 为两个地理位置。
最后一个距离单位参数说明:
- m :米,默认单位。
- km :千米。
- mi :英里。
- ft :英尺。
127.0.0.1:6379> GEODIST china:city beijing henan km # 查看北京到河南的距离
"621.8822"
127.0.0.1:6379> GEODIST china:city beijing shanghai km # 查看北京到上海的距离
"1067.3788"
127.0.0.1:6379>
georadius、georadiusbymember
- georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
- georadiusbymember 和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。
- georadius 与 georadiusbymember 语法格式如下:
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
- 参数说明:
-
- m :米,默认单位。
- km :千米。
- mi :英里。
- ft :英尺。
- WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
- WITHCOORD: 将位置元素的经度和纬度也一并返回。
- WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
- COUNT 限定返回的记录数。
- ASC: 查找结果根据距离从近到远排序。
- DESC: 查找结果根据从远到近排序
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km # 以110,30这个经纬度为中心,寻找方圆1000KM你的城市
1) "guangzhou"
2) "henan"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist # 显示到中心距离的位置
1) 1) "guangzhou"
2) "831.7713"
2) 1) "henan"
2) "630.2160"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord # 显示他人的定位信息
1) 1) "guangzhou"
2) 1) "113.27999979257583618"
2) "23.1199990030198208"
2) 1) "henan"
2) 1) "113.65999907255172729"
2) "34.74999926510690784"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist withcoord count 1 # 筛选出指定的结果
1) 1) "henan"
2) "630.2160"
3) 1) "113.65999907255172729"
2) "34.74999926510690784"
# 找出位于指定元素周围的其他元素
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1) "henan"
2) "beijing"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 1000 km
1) "shanghai"
2) "henan"
8.2、Hyperloglog
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
下表列出了 redis HyperLogLog 的基本命令:
序号 | 命令及描述 |
---|---|
1 | PFADD key element [element ...] 添加指定元素到 HyperLogLog 中。 |
2 | PFCOUNT key [key ...] 返回给定 HyperLogLog 的基数估算值。 |
3 | PFMERGE destkey sourcekey [sourcekey ...] 将多个 HyperLogLog 合并为一个 HyperLogLog |
127.0.0.1:6379> PFADD runoobkey "redis" "mongodb" "mysql" # 创建第一组元素
(integer) 1
127.0.0.1:6379> PFCOUNT runoobkey # 统计runoobkey 元素的基数数量
(integer) 3
127.0.0.1:6379> PFADD myset "redis" "mysql" "java" # 创建第二组 myset
(integer) 1
127.0.0.1:6379> PFMERGE mykey myset runoobkey # 合并两组
OK
127.0.0.1:6379> PFCOUNT mykey
(integer) 4
8.3、Bitmaps
使用bitmaps来记录一周的打卡
查看某天是否打卡
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> getbit sign 6
(integer) 0
统计操作,统计打卡的天数
127.0.0.1:6379> bitcount sign # 统计这周打卡的天数
(integer) 3
九、事务
Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在食物执行过程中,会按照顺序执行!
一次性、顺序性、排他性!
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。(MULTI)
- 命令入队。
- 执行事务。(EXEC)
Redis事务没有隔离级别的概念
Redis单条命令保证原子性,但事务不保证原子性
Redis 事务命令
下表列出了 redis 事务的相关命令:
序号 | 命令及描述 |
---|---|
1 | DISCARD 取消事务,放弃执行事务块内的所有命令。 |
2 | EXEC 执行所有事务块内的命令。 |
3 | MULTI 标记一个事务块的开始。 |
4 | UNWATCH 取消 WATCH 命令对所有 key 的监视。 |
5 | WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
127.0.0.1:6379> MULTI # 开启事务
OK
# 命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> EXEC # 执行事务
1) OK
2) OK
3) "v2"
4) OK
放弃事务
127.0.0.1:6379> MULTI # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> DISCARD #放弃事务
OK
127.0.0.1:6379> get k4 # 事务中的所有命令都不会被执行
(nil)
编译型异常(代码有问题,命令有错)事务中所有的命令都不会被执行
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> EXEC # 执行事务报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4 # 所有命令都不会被执行
(nil)
运行时异常!如果事务队列中存在与发行错误,那么执行命令的时候,其他命令可以执行,错误命令抛出异常
127.0.0.1:6379> set k1 "hello"
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR k1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
监控!
# Redis监控测试
127.0.0.1:6379> set money 100
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(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20
QUEUED
127.0.0.1:6379(TX)> EXEC
1) (integer) 80
2) (integer) 20