102.【Redis】(四)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 102.【Redis】

5、Hash (哈希)

集合中的元素是唯一的,这就意味着集合中不能出现重复的数据。在Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。Hash更适合于对象的存储。本质和String类型是没有太大区别的,还是一个简单的key-value.

127.0.0.1:6379> hset myhash filed1 jsxs  #设置单个hashMap
(integer) 1
127.0.0.1:6379> HGET myhash filed1 #得到一个hashMap
"jsxs"
127.0.0.1:6379> HMSET myhash filed1 "hello" filed2 "world" #设置多个hashMap
OK
127.0.0.1:6379> HGET myhash filed1
"hello"
127.0.0.1:6379> HMGET myhash filed1 filed2  #获取多个hashMap
1) "hello"
2) "world"
127.0.0.1:6379> HGETALL myhash  # 获得所有的hashMap
1) "filed1"
2) "hello"
3) "filed2"
4) "world"
------------------------------------------
删除指定的hashMap
127.0.0.1:6379> HDEL myhash filed2  #删除指定的hashmap
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "filed1"
2) "hello"
------------------------------------------
查看有几个键值对
127.0.0.1:6379> HLEN myhash
(integer) 1
127.0.0.1:6379> HMSET myhash filed2 world filed3 hh
OK
127.0.0.1:6379> HGETALL myhash
1) "filed1"
2) "hello"
3) "filed2"
4) "world"
5) "filed3"
6) "hh"
127.0.0.1:6379> HLEN myhash # 获取hash表的字段数量
(integer) 3
------------------------------------------
hash中指定字段是否存在
127.0.0.1:6379> HEXISTS myhash files1  #判断hash是否存在
(integer) 0
127.0.0.1:6379> HEXISTS myhash filed1
(integer) 1
------------------------------------------
仅仅获取字段和值
127.0.0.1:6379> HKEYS myhash  # 单纯获取字段
1) "filed1"
2) "filed2"
3) "filed3"
127.0.0.1:6379> HVALS myhash #单纯获取值
1) "hello"
2) "world"
3) "hh"
------------------------------------------
127.0.0.1:6379> HSET myhash fileds3 5  
(integer) 1
127.0.0.1:6379> HINCRBY myhash fileds3 1  # 自增1
(integer) 6
127.0.0.1:6379> HINCRBY myhash fileds3 2  #自自增2
(integer) 8
127.0.0.1:6379> HINCRBY myhash fileds3 -1 # 自减1
(integer) 7
127.0.0.1:6379> HSETNX myhash filed4 hello #加入说不存在就创建,存在就不创建
(integer) 1
127.0.0.1:6379> HSETNX myhash filed4 hello
(integer) 0

hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!

127.0.0.1:6379> HSET user:1 name jsxs  # 设置id为1 键值对name 
(integer) 1
127.0.0.1:6379> HGET myhash user:1
(nil)
127.0.0.1:6379> HGET user:1 name  #获取id为1 的键值对
"jsxs"

6、Zset (有序集合)

在set基础上,增加一个值。set k1 v1 | zset k1 score1 v1

# 添加值
127.0.0.1:6379> zadd myset 1 one  # 添加一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zadd myset 3 three 4 four  #添加多个值
(integer) 2
127.0.0.1:6379> ZRANGE myset 0-1
(error) ERR wrong number of arguments for 'zrange' command
127.0.0.1:6379> ZRANGE myset 0 -1  # 查看添加的值
1) "one"
2) "two"
3) "three"
4) "four"
------------------------------------------
根据score 进行排序
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf  # 范围是正无穷 到 负无穷升序排序
1) "jsxs"
2) "xiaoming"
3) "zahngsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 范围是正无穷 到 负无穷升序排序 并显示分数
1) "jsxs"
2) "200"
3) "xiaoming"
4) "2500"
5) "zahngsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores # 范围是正无穷 到 2500
1) "jsxs"
2) "200"
3) "xiaoming"
4) "2500"
127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf withscores # 范围是正无穷 到 负无穷降序排序 并显示分数
1) "zahngsan"
2) "5000"
3) "xiaoming"
4) "2500"
5) "jsxs"
6) "200"
------------------------------------------
移除指定元素
127.0.0.1:6379> ZRANGE salary 0 -1
1) "jsxs"
2) "xiaoming"
3) "zahngsan"
127.0.0.1:6379> ZREM salary xiaoming  # 移除指定的元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "jsxs"
2) "zahngsan"
127.0.0.1:6379> zcard salary  # 查看长度
(integer) 2
------------------------------------------
获取指定区间的个数
127.0.0.1:6379> zadd myset 1 "hello"  #
(integer) 1
127.0.0.1:6379> zadd myset 2 "world" 3 ".jsxs"
(integer) 2
127.0.0.1:6379> ZCOUNT myset 1 3   # 获取1-3区间之间的数量
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 2  # 获取1-2区间之间的数量
(integer) 2

应用案例:

set排序 存储班级成绩表 工资表排序

普通消息1 重要消息 2 ----带权重进行判断!

排行榜应用实现,取Top N测试!

(四)、三种特殊数据类型

1、Geospatial(地理位置)

使用经纬度定位地理坐标,并用一个有序集合Zset进行保存,GEO的底层实现原理就是Zset

在这里我们先来增加一个经纬度的基本常识:

超链接: 在线经纬度查询工具

  • 有效的经度从-180度到180度
  • 有效的纬度从-85.05112878度到85.05112878度

1.geoAdd 添加地址

添加地理位置: 
geoadd key 值(经度,维度,名称)
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 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzhen
(integer) 1
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2

2.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 beijing chongqing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"

3.geoDist 获取两点的距离

  • m :米
  • km :千米
  • mi :英里
  • ft :英尺
两点之间的距离
127.0.0.1:6379> GEODIST china:city beijing xian km   # 北京到西安的千米
"910.0565"
127.0.0.1:6379> geoadd china:city 114.60 33.53 zhoukou
(integer) 1
127.0.0.1:6379> GEODIST china:city beijing zhoukou
"726411.7341"
127.0.0.1:6379> GEODIST china:city beijing zhoukou km  #北京到周口的km
"726.4117"

3.geoRadius 以给定的经纬度为中心,找出某一半径的元素

(我附近的人?) 获得所有附件的人的地址,定位! 通过半径来查询。

多用于找朋友

根据经纬度查找附近的城市
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km  # 查找以经度110 维度30 长度为1000km的城市
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "zhoukou"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist # 查找以经度110 维度30 长度为500km的城市 并标出直线距离
1) 1) "chongqing"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord # 查找以经度110 维度30 长度为500km的城市 并标出经纬度
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1# 查找以经度110 维度30 长度为500km的城市 并标出直线距离 经纬度以及最近的一个。
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
  1. geoRadiusByMber 找出指定范围的元素,中心点是给定的元素

多用于找城市

根据地名向附近查找:  
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km #以北京为中心半径为1000km查找所有的城市
1) "zhoukou"
2) "beijing"
3) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 1000 km
1) "hangzhou"
2) "shanghai"
3) "zhoukou"

5.geoHash 命令- 返回一个或多个位置元素的geoHash表示

该命令将返回11个字符的GeoHash字符串!

将二纬的经纬度转换为以为的字符串.如果两个字符串越接近,那么距离越近
127.0.0.1:6379> GEOHASH china:city beijing
1) "wx4fbxxfke0"
127.0.0.1:6379> GEOHASH china:city beijing zhoukou
1) "wx4fbxxfke0"
2) "wtcqxzcnmt0"

GEO 底层的实现原理其实就是 Zset!我们可以使用Zset命令来对其进行相关操作.

验证: 我们可以利用Zset进行删除的操作

移除坐标
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "zhoukou"
7) "beijing"
127.0.0.1:6379> ZREM china:city shenzhen   #移除坐标
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqing"
2) "xian"
3) "hangzhou"
4) "shanghai"
5) "zhoukou"
6) "beijing"

2、Hyperloglog(基数统计)

基数就是一个集合中不重复的元素。举一个简单的例子:

  • A {1,3,5,7,8,7}
  • A(不重复的元素) = (1,3,5,8),可以接受误差!

简介

  • Redis HyperLogLog 是用来做基数统计的算法。
  • 优点:
  • 输入元素的数量或者体积非常大时,计算基数所需的空间总是固定的、并且是很小的。
  • 花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。

网页的UV (一个人访问一个网站多次,但是还是算作一个人!)

  1. 传统的解决方式: 利用set集合不重复的特性。set保存用户的id,然后就可以统计元素数量作为标准判断!
  2. 如果允许容错,那么一定可以使用 Hyperloglog 。
  3. 如果不允许容错,就使用传统的 set 或者自己的数据类型即可。
  4. HyperLogLog 底层使用string数据类型。
127.0.0.1:6379> PFADD myset a b c d e f g h i j k  #设置一个基数统计
(integer) 1
127.0.0.1:6379> PFCOUNT myset  #统计不重复的数量-基数
(integer) 11
127.0.0.1:6379> PFADD myset2 a b c d e f g h i j k s a a c b
(integer) 1
127.0.0.1:6379> PFCOUNT myset
(integer) 11
127.0.0.1:6379> PFCOUNT myset2
(integer) 12
127.0.0.1:6379> PFMERGE mykey3 myset myset2  # 进行多个集合的合并
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 12

3、BitMap(位图)

BitMap可以用来干什么呢?

  • 签到统计,使用bitmap 来记录 周一到周日的打卡!
  • 状态统计

BitMap采用位存储,它是一连串的二进制数字,信息状态只有0和1,每一位所在的位置为(offset)

测试: 假设我们现在的任务是统计从星期一到星期天的打卡情况。0代表未打卡,1代表打卡

------------------------------------------
添加一个
127.0.0.1:6379> setbit sign 0 0  # 假设第一个0是星期1 第二个0 是未打卡
127.0.0.1:6379> setbit sign 1 0
(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 1
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
------------------------------------------
查看某一个具体的
127.0.0.1:6379> GETBIT sign 0
(integer) 0
127.0.0.1:6379> GETBIT sign 3
(integer) 1
127.0.0.1:6379> GETBIT sign 6
(integer) 1
------------------------------------------
统计总和就是 0和1 的
127.0.0.1:6379> BITCOUNT sign
(integer) 5

(五)、事务

面试高频:

这里我们一定要知道Redis中的单条命令是保证原子性的,但是redis事务不能保证原子性

Redis事务的本质

  • 一次性
  • 顺序性
  • 排他性
    在Redis事务没有没有隔离级别的概念;所有的命令在事务中,并没有直接被执行!只有发起执行命令Exec的时候才会执行!

事务中每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰(排他)

redis事务的三大过程

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

1.正常执行事务

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

2.取消事务

取消事务,代表事务里面的数据不奏效。但以前的数据仍然保留。

127.0.0.1:6379> get k2 # 事务
"v2"
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)
127.0.0.1:6379> get k2 # 事务之前的有效
"v2"

3.编译型异常(代码有问题, 命令有错!)

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

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 k3 v3
QUEUED
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 k1  # 得不到值
(nil)

4.运行时异常 (错误的不被执行,其他的执行)

如果事务队列中存在错误语法性,那么执行命令的时候,其他命令是可以正常执行的,只有错误命令会抛出异常!

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set k1 "v1"
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)> EXEC
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
18天前
|
NoSQL Redis
redis红锁
在Redis集群中,若请求分布式锁成功后Master宕机且Slave未同步此锁,会导致锁被多次获取。为解决此问题,可对集群每个节点加锁,当大多数节点(N/2+1)加锁成功时,视为获取锁成功。尽管Redisson实现了红锁,但其无法确保每个锁分布在不同Master上,因此建议直接使用Redisson的普通锁。
30 5
|
7月前
|
存储 NoSQL 测试技术
【Redis】redis为什么快
【Redis】redis为什么快
|
5月前
|
缓存 负载均衡 NoSQL
这样学Redis,才能技高一筹
【7月更文挑战第18天】
58 3
|
运维 NoSQL Shell
redis(2)
Redis Cluster 是 redis的分布式解决方案,在3.0版本正式推出 当遇到单机、内存、并发、流量等瓶颈时,可以采用Cluster架构方案达到负载均衡目的。 Redis Cluster之前的分布式方案有两种: 1)客户端分区方案: 优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等。 2)代理方案: 优点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署和性能消耗。 官方提供的 Redis Cluster集群方案,很好的解决了集群方面的问题
|
7月前
|
存储 人工智能 NoSQL
Redis的未来
【翻译】来自redis官网对未来的规划
256 0
|
NoSQL 安全 Redis
|
消息中间件 缓存 NoSQL
Redis总结
Redis总结
43 0
|
NoSQL Redis
|
存储 消息中间件 NoSQL
|
存储 消息中间件 缓存
Redis总结(二)
redis 和 memcached 什么区别?为什么高并发下有时单线程的 redis 比多线程的memcached 效率要高?区别:1.mc 可缓存图片和视频。rd 支持除 k/v 更多的数据结构;2.rd 可以使用虚拟内存,rd 可持久化和 aof 灾难恢复,rd 通过主从支持数据备份;3.rd 可以做消息队列。原因:mc 多线程模型引入了缓存一致性和锁,加锁带来了性能损耗。redis 主从复制如何实现的?redis 的集群模式如何实现?redis 的 key 是如何寻址的?
107 0