Redis
Posted 默辨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis相关的知识,希望对你有一定的参考价值。
文章目录
5、三种特殊的数据类型
5.1、geospatial地理位置
Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增
主要分为6个指令
- geoadd(将指定的地理空间位置空添加到指定的key中)
- geodist(返回两个给定位置之间的距离)
- geohash(返回一个或多个位置对象的 geohash 值)
- geopos(返回指定地理名称的经纬度)
- georadius(返回指定经纬度范围内的城市信息)
- 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事务开启方式:
- 开启事务(multi)
- 命令入队
- 执行事务(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测试乐观锁,步骤如下:
- 分别打开两个Redis客户端
- 客户端1设置money变量的值为100
- 客户端2获取设置的money变量值
- 客户端1使用watch给money变量添加监控(对比理解乐观锁的实现,更行money变量时添加一个version条件控制)
- 客户端1开启事务
- 客户端1修money的值
- 客户端2修改money变量的值
- 客户端1执行事务(由于客户端2修改了money的值,即监控的money字段其version字段发生了改变,所以执行事务失败)
- 客户端1获取money变量的值(由于客户端1的事务操作失败,所以money值为客户端2中修改后的值)
- 客户端2获取money变量的值(由于客户端1的事务操作失败,所以money值为客户端2中修改后的值)
如果修改失败,解锁后重新加锁再次操作即可。这里优点类似于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配制方法