Redis

Posted 默辨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis相关的知识,希望对你有一定的参考价值。





5、三种特殊的数据类型

5.1、geospatial地理位置

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增

win版本3.2下载地址

主要分为6个指令

  1. geoadd(将指定的地理空间位置空添加到指定的key中)
  2. geodist(返回两个给定位置之间的距离)
  3. geohash(返回一个或多个位置对象的 geohash 值)
  4. geopos(返回指定地理名称的经纬度)
  5. georadius(返回指定经纬度范围内的城市信息)
  6. georadiusbymember(返回已存在城市指定范围内的城市信息)



GEOADD:将指定的地理空间位置空添加到指定的key中

具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:

  • 有效的经度从-180度到180度。
  • 有效的纬度从-85.05112878度到85.05112878度。
  • 添加格式为——经度、纬度、名称

当坐标位置超出上述指定范围时,该命令将会返回一个错误。

# 使用geoadd添加五个城市的地理位置数据

127.0.0.1:6379> geoadd city 106.54 29.40 chongqing
(integer) 1
127.0.0.1:6379> geoadd city 104.64 28.75 sichuan
(integer) 1
127.0.0.1:6379> geoadd city 120.21 30.25 hangzhou
(integer) 1
127.0.0.1:6379> geoadd city 125.15 42.93 xian
(integer) 1
127.0.0.1:6379> geoadd city 114.06 22.54 shenzhen
(integer) 1



GEODIST:返回两个给定位置之间的距离

如果两个位置之间的其中一个不存在, 那么命令返回空值。

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

# 计算两个城市之间的距离

127.0.0.1:6379> GEODIST city chongqing sichuan
"198341.1791"

127.0.0.1:6379> GEODIST city hangzhou chongqing
"1321660.7039"

127.0.0.1:6379> GEODIST city xian hangzhou km  # 默认的单位是m,可以显示的指定距离单位为km
"1477.0109"

127.0.0.1:6379> GEODIST city xian hangzhou
"1477010.8848"



GEOHASH:返回一个或多个位置对象的 geohash 值

# 返回指定地理位置的geohash值

127.0.0.1:6379> GEOHASH city chongqing sichuan
1) "wm5z22h53v0"
2) "wm47t1u8bs0"

127.0.0.1:6379> GEOHASH city chongqing sichuan xian
1) "wm5z22h53v0"
2) "wm47t1u8bs0"
3) "wz8upz5mqk0"
127.0.0.1:6379>



GEOPOS:返回一个数组,数组中每一项都由两个元素组成(精度、维度),如果元素不存在,对应的数组项为空制

# 返回指定地理名称的地理经纬度值

127.0.0.1:6379> GEOPOS city chongqing shanghai xian
1) 1) "106.54000014066696"
   2) "29.399998800186417"
2) (nil)
3) 1) "125.14999777078629"
   2) "42.930000696102383"
   
127.0.0.1:6379> GEOPOS city hangzhou
1) 1) "120.21000176668167"
   2) "30.249999797922619"



GEORADIUS:返回指定经纬度范围内的城市信息

GEORADIUSBYMEMBER:返回已存在城市信息范围内的其他城市信息

参数说明

  • m :米,默认单位。

  • km :千米。

  • mi :英里。

  • ft :英尺。

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。

  • WITHCOORD: 将位置元素的经度和维度也一并返回。

  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。

  • COUNT 限定返回的记录数。

  • ASC: 查找结果根据距离从近到远排序。

  • DESC: 查找结果根据从远到近排序。

# georadius 返回以经度为100 纬度为25的为原点,100km范围内的城市信息

127.0.0.1:6379>  georadius city 100 25 100 km
(empty list or set)
127.0.0.1:6379>  georadius city 100 25 1000 km
1) "sichuan"
2) "chongqing"

127.0.0.1:6379>  georadius city 100 25 1000 km withcoord
1) 1) "sichuan"
   2) 1) "104.63999837636948"
      2) "28.749999975527849"
2) 1) "chongqing"
   2) 1) "106.54000014066696"
      2) "29.399998800186417"
    
# 位置元素与中心之间的距离也一并返回
127.0.0.1:6379>  georadius city 100 25 1000 km withdist
1) 1) "sichuan"
   2) "621.0759"
2) 1) "chongqing"
   2) "810.9416" 

# 将位置元素的经度和维度也一并返回
127.0.0.1:6379>  georadius city 100 25 1000 km withcoord withdist
1) 1) "sichuan"
   2) "621.0759"
   3) 1) "104.63999837636948"
      2) "28.749999975527849"
2) 1) "chongqing"
   2) "810.9416"
   3) 1) "106.54000014066696"
      2) "29.399998800186417"
# georadiusbymember 以chongqing为原点,范围1000km以内的城市信息

127.0.0.1:6379> georadiusbymember city chongqing 1000 km
1) "sichuan"
2) "chongqing"

# 将位置元素的经度和维度也一并返回
127.0.0.1:6379> georadiusbymember city chongqing 1000 km withcoord
1) 1) "sichuan"
   2) 1) "104.63999837636948"
      2) "28.749999975527849"
2) 1) "chongqing"
   2) 1) "106.54000014066696"
      2) "29.399998800186417"
      
# 将位置元素的经度和维度也一并返回,由远及近排列
127.0.0.1:6379> georadiusbymember city chongqing 1000 km withcoord desc
1) 1) "sichuan"
   2) 1) "104.63999837636948"
      2) "28.749999975527849"
2) 1) "chongqing"
   2) 1) "106.54000014066696"
      2) "29.399998800186417"
      
127.0.0.1:6379> georadiusbymember city chongqing 1000 km withcoord asc
1) 1) "chongqing"
   2) 1) "106.54000014066696"
      2) "29.399998800186417"
2) 1) "sichuan"
   2) 1) "104.63999837636948"
      2) "28.749999975527849"

127.0.0.1:6379> georadiusbymember city chongqing 1000 km withcoord withhash
1) 1) "sichuan"
   2) (integer) 4025121096646710
   3) 1) "104.63999837636948"
      2) "28.749999975527849"
2) 1) "chongqing"
   2) (integer) 4026043655521786
   3) 1) "106.54000014066696"
      2) "29.399998800186417"

# 返回一条结果集
127.0.0.1:6379> georadiusbymember city chongqing 1000 km withcoord count 1 
1) 1) "chongqing"
   2) 1) "106.54000014066696"
      2) "29.399998800186417"
127.0.0.1:6379>




5.2、Hyperloglog基数统计

以下解释来源菜鸟教程:

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。Redis 在 2.8.9 版本添加了 HyperLogLog 结构

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素

什么是基数:数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

# 基数统计

127.0.0.1:6379> PFADD myset 1 2 3 3 1 2 22 123 323 11
(integer) 1
127.0.0.1:6379> PFCOUNT myset
(integer) 7
127.0.0.1:6379> PFADD myset2 2 1 22 333 45 7 7
(integer) 1
127.0.0.1:6379> PFCOUNT myset2
(integer) 6

# 将myset和myset2进行合并
127.0.0.1:6379> PFMERGE myset myset2
OK
# 可以对合并以后的集合进行基数统计,去掉两个集合中重复的元素以后总数为10个
127.0.0.1:6379> PFCOUNT myset
(integer) 10

注意:如果统计的数据不允许容错,那么就不能使用Hyperloglog进行基数的统计




5.3、Bitmap位存储

从Redis从2.2.0版本开始,Redis新增了setbit、getbit、bitcount等几个与bitmap相关的命令。因为这些命令都是在set命令的基础上扩展而来,所以并没有新增新的数据类型。

Bitmap就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。且其能够极大的节省储存空间

# 模拟一周内的上线情况,1表示上线了,0表示未上线
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 0
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0

# 获取指定的星期日子的上线情况
127.0.0.1:6379> getbit sign 4
(integer) 0
127.0.0.1:6379> getbit sign 6
(integer) 1

# 统计一周内总的上线天数,即sign为1的数量
127.0.0.1:6379> bitcount sign
(integer) 5






6、事务

6.1、事务基本操作

Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程种,会按照顺序执行

Redis事务的特点:一次性、顺序性、排它性。可以将它抽象的理解为一个队列

------ 开启  set set set  执行 ------

Redis事务没有隔离级别概念,Redis单条命令是保证原子性的,但是Redis的事务不保证原子性

Redis事务开启方式:

  1. 开启事务(multi)
  2. 命令入队
  3. 执行事务(exec)

正常执行事务:exec

127.0.0.1:6379> multi   # 开启事务
OK
127.0.0.1:6379> set name mobian
QUEUED
127.0.0.1:6379> set age 11
QUEUED
127.0.0.1:6379> set sex 1
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> exec  # 结束事务,一次执行进入队列中的命令
1) OK
2) OK
3) OK
4) "11"
5) "mobian"



放弃事务:discard

127.0.0.1:6379> multi   # 开启事务
OK
127.0.0.1:6379> set name mobian 
QUEUED
127.0.0.1:6379> discard   # 放弃事务
OK
127.0.0.1:6379> get name
(nil)



编译型异常:代码语法有问题,命令有误。事务中所有的命令都不会被执行

127.0.0.1:6379> multi   # 开启事务
OK
127.0.0.1:6379> set name1 mobian1
QUEUED
127.0.0.1:6379> set name2 mobian2
QUEUED
127.0.0.1:6379> setset  name3 mobian3    # 代码语法有误,出现编译型异常
(error) ERR unknown command 'setset'
127.0.0.1:6379> set name4 mobian4
QUEUED
127.0.0.1:6379> exec     # 执行事务,报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name1       # 获取由于出现编译型异常,导致事务中的所有命令都不会被执行,所以获取不到数据
(nil)



执行时异常:代码正确,但执行会报异常,如对字符串+1。事务中的其他命令不受影响

127.0.0.1:6379> multi   # 开启事务
OK
127.0.0.1:6379> set name1 mobian1
QUEUED
127.0.0.1:6379> incr name1  # 给一个非数字的key执行+1操作
QUEUED
127.0.0.1:6379> set name2 mobian2
QUEUED
127.0.0.1:6379> exec  # 执行事务,第二步报异常
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> get name2  # 由于前面是执行时异常并非编译型异常,所以其他的set操作不受影响 
"mobian2"




6.2、Redis实现乐观锁

关键词:watch

使用watch关键词,对变量进行监控,以达到常规实现乐观锁操作的版本字段控制

使用Redis测试乐观锁,步骤如下:

  1. 分别打开两个Redis客户端
  2. 客户端1设置money变量的值为100
  3. 客户端2获取设置的money变量值
  4. 客户端1使用watch给money变量添加监控(对比理解乐观锁的实现,更行money变量时添加一个version条件控制)
  5. 客户端1开启事务
  6. 客户端1修money的值
  7. 客户端2修改money变量的值
  8. 客户端1执行事务(由于客户端2修改了money的值,即监控的money字段其version字段发生了改变,所以执行事务失败)
  9. 客户端1获取money变量的值(由于客户端1的事务操作失败,所以money值为客户端2中修改后的值)
  10. 客户端2获取money变量的值(由于客户端1的事务操作失败,所以money值为客户端2中修改后的值)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPFTZFyi-1622439644845)(Redis(二).assets/image-20210528201243268.png)]



如果修改失败,解锁后重新加锁再次操作即可。这里优点类似于CAS锁的操作。

加锁…解锁 。。 加锁…解锁 。。。。。。

127.0.0.1:6379> unwatch
OK






7、Jedis

7.1、简介

Java语言与Redis服务进行连接




7.2、入门案例

1、创建一个maven项目

2、添加对应的maven依赖

<!--对应的jedis依赖-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

3、启动后台的Redis服务

4、编写一个测试类

public class Test {
	public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);

		System.out.println(jedis.ping());
	}
}

测试结果:

PONG




7.3、key的基本操作

public class Key {
	public static void main(String[] args) {
		Jedis jedis = new Jedis("127.0.0.1", 6379);

		System.out.println("判断对应的key键是否存在:" + jedis.exists("name"));
		System.out.println("添加数据:" + jedis.set("name", "mobian"));
		System.out.println("添加数据:" + jedis.set("city", "chongqing"));
		System.out.println("获取系统所有的键:" + jedis.keys("*"));

		System.out.println("根据key删除对应的数据:" + jedis.del("name"));
		System.out.println("判断对应的key是否存在:" + jedis.exists("name"));
		System.out.println("判断key的类型:" + jedis.type("city"));

		System.out.println("随机返回一个key:" + jedis.randomKey());//需要添加大于一个的key才能完成测试

		System.out.println("重新命名对应的key" + jedis.rename("city", "newcity"));
		System.out.println(jedis.get("newcity"));

		System.out.println("选择使用1号数据库" + jedis.select(1));
		System.out.println("获取系统所有的键:" + jedis.keys("*"));

		System.out.println("选择使用0号数据库" + jedis.select(0));
		System.out.println("获取系统所有的键:" + jedis.keys("*"));

		System.out.println("获取当前数据库key的数目" + jedis.dbSize());
		System.out.println("清空当前数据库" + jedis.flushDB());
		System.out.println("清空所有数据库" + jedis.flushAll());

		System.out.println("获取系统所有的键:" + jedis.keys("*"));

	}
}

测试结果:

判断对应的key键是否存在:false
添加数据:OK
添加数据:OK
获取系统所有的键:[name, city]
根据key删除对应的数据:1
判断对应的key是否存在:false
判断key的类型:string
随机返回一个key:city
重新命名对应的keyOK
chongqing
选择使用1号数据库OK
获取系统所有的键:[]
选择使用0号数据库OK
获取系统所有的键:[newcity]
获取当前数据库key的数目1
清空当前数据库OK
清空所有数据库OK
获取系统所有的键:[]




7.4、String的基本操作

public class String {
	public static void main(java.lang.String[] args) throws InterruptedException {
		Jedis jedis = new Jedis("127.0.0.1", 6379);
		jedis.set("k1", "v1");
		jedis.set("k2", "v2");
		jedis.set("k3", "v3");

		System.out.println("删除键k1:" + jedis.del("k1"));
		System.out.println("获取键k2:" + jedis.get("k2"));
		System.out.println("修改键k3的值:" + jedis.set("k3", "newV3"));

		System.out.println("k3键的值后添加信息:" + jedis.append("k3", "_appendV3"));
		System.out.println("获取键k2:" + jedis.get("k3"));

		System.out.println("=================测试批量操作======================");
		System.out.printlnredis存储session配制方法

Redis实现分布式锁(设计模式应用实战)

Redis实现分布式锁(设计模式应用实战)

Redis缓存:java语言注释符号,附超全教程文档

spring boot 整合 redis

Redis 学习 —— 数据类型及操作