前言:

推荐免费Redis基础讲解视频:【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩_bilibili

Geospatial地理位置详解

经纬度查询:腾讯位置服务 - 立足生态,连接未来 (qq.com)

GEOADD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加地理位置 
# 经度 纬度 城市名
# 纬度有效范围为-85 到 +85
# 经纬度有效范围为-180 到 +180
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 108.96 34.29 xian
(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 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1

GEOPOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 获取有效的经纬度
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city xian
1) 1) "108.96000176668167114"
2) "34.29000060383123838"
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.47000163793563843"
2) "31.22999903975783553"
127.0.0.1:6379> geopos china:city chongqing
1) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> geopos china:city hangzhou
1) 1) "120.1600000262260437"
2) "30.2400003229490224"

GEODIST

1
2
3
4
5
6
7
8
# 返回两个给定位置之间的距离
# 单位:m(米) km(千米) mi(英里) ft(英尺)
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.3788"
127.0.0.1:6379> geodist china:city beijing xian km
"907.6700"

GEORADIUS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 以给定的经度纬度为中心,找出某一半径内的元素 
# 使用:附近的人,附近的好友等
127.0.0.1:6379> georadius china:city 110 30 1000 km # 获取110~30范围内 1000km
1) "chongqing"
2) "xian"
3) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km # 获取110~30范围内 500km
1) "chongqing"
2) "xian"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 显示直线距离
1) 1) "chongqing"
2) "341.9374"
2) 1) "xian"
2) "487.0990"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord # 显示经纬度
1) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
2) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.29000060383123838"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord count 1 # 显示经纬度,并控制显示数量为1
1) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"

GEORADIUSBYMEMBER

1
2
3
4
# 找出位于指定范围内的元素,中心点是由给定位置元素决定的
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
2) "xian"

GEOHASH

1
2
3
4
# 返回一个或多个位置元素的Geohash表示
127.0.0.1:6379> geohash china:city beijing xian
1) "wx4fbxxfke0" # 当前城市经纬度的字符串
2) "wqj7p6q38p0"# 当前城市经纬度的字符串

geo的底层使用Zset,可以使用Zset命令来操作;

Hyperloglog基数统计

基数:集合论中刻画任意集合大小的一个概念;

简介

Hyperloglog是一种数据结构,用来做基数统计的算法;

如:统计网站UV

传统方式:使用set保存用户ID,来进行统计,但是本质是为了统计访问量;

Hyperloglog:占用内存固定,2^64只需要占用12kb内存;会有0.81%的错误率(但统计人数可以接收);

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
(integer) 25
127.0.0.1:6379> pfadd my a b c
(integer) 1
127.0.0.1:6379> pfadd my2 b c d
(integer) 1
127.0.0.1:6379> pfcount my
(integer) 3
127.0.0.1:6379> pfcount my2
(integer) 3
127.0.0.1:6379> pfmerge myc my my2 # 合并为myc
OK
127.0.0.1:6379> pfcount myc # 合并后长度
(integer) 4

Bitmap位图场景详解

位存储

简介

Bitmap 位图,数据结构!都是操作二进制位!代表了有限域中的稠集(dense set),每一个元素至少出现一次,没有其他的数据和元素相关联。在索引,数据压缩等方面有广泛应用。

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 一周打卡记录 0代表未打卡 1代表打卡
127.0.0.1:6379> clear
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 1
(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>
# 统计打卡天数
127.0.0.1:6379> bitcount sign
(integer) 4
127.0.0.1:6379> bitcount sign 0 6
(integer) 4

Redis基本的事务操作

所学事务:ACID原则(原子性,一致性,隔离性,持久性)

概述

Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令

Redis的单条命令是保证选自性的,单事务不能保证原子性

Redis事务没有隔离级别的概念

Redis事务步骤:

  • 开启事务(multi)
  • 命令入队
  • 执行事务(exec)

正常执行事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

放弃事务

1
2
3
4
5
6
7
8
9
10
11
12
13
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 k4 v4
QUEUED
127.0.0.1:6379(TX)> discard # 放弃事务
OK
127.0.0.1:6379> get k4
(nil) # 说明命令没有被执行

编译型异常

事务中所有命令都不会执行;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 v5
QUEUED
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务直接报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5 # 事务中的所有命令都未执行
(nil)

运行时异常

错误命令不会执行并抛出异常,其他命令不受影响;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 "v1"
QUEUED
127.0.0.1:6379(TX)> incr k1 # k1为字符串,对它+1一定不会成功
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) OK
2) (error) ERR value is not an integer or out of range # 可以看到只有这一项报错了,其他事务没受到影响
3) OK
4) OK
5) "v3"

Redis实现乐观锁

概述

悲观锁:认为什么时候都会有问题,无论做什么都加锁;

乐观锁:认为什么时候都不会有问题,所以一般不会上锁,只在数据更新的时候去判断一下,在此期间是否有人修改过这个数据!

Redis监控 Watch

正常执行成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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

执行出现问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 我们复制一个会话,同时连接两个redis-cli
# 会话一
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 10
QUEUED
127.0.0.1:6379(TX)> incrby out 10
QUEUED
127.0.0.1:6379(TX)>
# 到这里不执行会话一的事务,而是打开会话二,修改money的值
# 会话二
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 100 # 修改money的值
OK
127.0.0.1:6379>
# 回到会话一
127.0.0.1:6379(TX)> exec # 执行事务
(nil) # 发现事务执行失败
# 解决这个问题
# 会话一
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(TX)> decrby money 1
QUEUED
127.0.0.1:6379(TX)> incrby out 1
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 99
2) (integer) 21
127.0.0.1:6379> get money
"99"
127.0.0.1:6379>