第124天学习打卡(Redis Set Hash Zset 三种特殊数据类型 事务 乐观锁)
2021/5/13 2:29:18
本文主要是介绍第124天学习打卡(Redis Set Hash Zset 三种特殊数据类型 事务 乐观锁),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Set(集合)
set中的值不能重复 set是无序的且不重复
127.0.0.1:6379> sadd myset "hello" # set集合中添加值 (integer) 1 127.0.0.1:6379> sadd myset "kuangshen" (integer) 1 127.0.0.1:6379> sadd myset "lovekuangshen" (integer) 1 127.0.0.1:6379> smembers myset #查看指定set的所有值 1) "hello" 2) "lovekuangshen" 3) "kuangshen" 127.0.0.1:6379> sismember myset hello# 判断某一个值是不是在set集合中,是的话返回1 不是返回0 (integer) 1 127.0.0.1:6379> sismember myset world (integer) 0 127.0.0.1:6379> scard myset #获取set集合中的内容元素个数 (integer) 3 127.0.0.1:6379> sadd myset "hello" # 如果set重复的值不会成功,因为set不能重复 (integer) 0 127.0.0.1:6379> sadd myset "hello2" (integer) 1 127.0.0.1:6379> scard myset (integer) 4 =========================================== #rem 127.0.0.1:6379> srem myset hello # 移除set集合中的指定元素 (integer) 1 127.0.0.1:6379> scard myset (integer) 3 127.0.0.1:6379> smembers myset 1) "hello2" 2) "lovekuangshen" 3) "kuangshen" ============================================ set 无序不重复集合。随机! 127.0.0.1:6379> smembers myset 1) "hello2" 2) "lovekuangshen" 3) "kuangshen" 127.0.0.1:6379> srandmember myset # 随机抽选出一个元素 "kuangshen" 127.0.0.1:6379> srandmember myset "kuangshen" 127.0.0.1:6379> srandmember myset "hello2" 127.0.0.1:6379> srandmember myset "lovekuangshen" 127.0.0.1:6379> srandmember myset 2# 随机抽选出指定个数的元素 1) "hello2" 2) "lovekuangshen" =================================================== 随机删除key! 127.0.0.1:6379> smembers myset 1) "hello2" 2) "lovekuangshen" 3) "kuangshen" 127.0.0.1:6379> spop myset # 随机移除一些set集合中的元素! "lovekuangshen" 127.0.0.1:6379> spop myset "hello2" 127.0.0.1:6379> smembers myset 1) "kuangshen" ====================================================== #将一个指定的值,移动到另外一个set集合中! 127.0.0.1:6379> sadd myset "hello" (integer) 1 127.0.0.1:6379> sadd myset "world" (integer) 1 127.0.0.1:6379> sadd myset "kuangshen" (integer) 1 127.0.0.1:6379> sadd myset2 "set2" (integer) 1 127.0.0.1:6379> smove myset myset2 "kuangshen"#将一个指定的值,移动到另外一个set集合中! (integer) 1 127.0.0.1:6379> smembers myset 1) "hello" 2) "world" 127.0.0.1:6379> smembers myset2 1) "kuangshen" 2) "set2" ==================================================== 微博 或者B站或者....有共同关注这个提示(这是个交集) 数学集合类: - 差集 sdiff - 交集 sinter - 并集 sunion 127.0.0.1:6379> sadd key1 a (integer) 1 127.0.0.1:6379> sadd key1 b (integer) 1 127.0.0.1:6379> sadd key1 c (integer) 1 127.0.0.1:6379> sadd key2 c (integer) 1 127.0.0.1:6379> sadd key2 d (integer) 1 127.0.0.1:6379> sadd key2 e (integer) 1 127.0.0.1:6379> sdiff key1 key2 # 差集 1) "a" 2) "b" 127.0.0.1:6379> sinter key1 key2 #交集 1) "c" 127.0.0.1:6379> sunion key1 key2 # 并集 1) "b" 2) "c" 3) "a" 4) "e" 5) "d"
Hash(哈希)
127.0.0.1:6379> hset myhash field1 kuangshen #set 一个具体的key-value (integer) 1 127.0.0.1:6379> hget myhash field1 "kuangshen" 127.0.0.1:6379> hmset myhash field1 hello field2 world OK # 如果field1 里面有值 那么现在set的值会覆盖前面的值 set多个key-value 127.0.0.1:6379> hmget myhash field1 field2 #获取多个字段的值 1) "hello" 2) "world" 127.0.0.1:6379> hgetall myhash #获取全部的值 以key-value形式 1) "field1" 2) "hello" 3) "field2" 4) "world" 127.0.0.1:6379> hdel myhash field1 #删除hash指定的key字段,对应的value值也就消失了 (integer) 1 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world" ==================================================== #hlen 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world" 127.0.0.1:6379> hlen myhash (integer) 1 127.0.0.1:6379> hmset myhash field1 hello field2 world# 如果field2 里面有值 那么现在set的值会覆盖前面的值 OK 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world" 3) "field1" 4) "hello" 127.0.0.1:6379> hlen myhash #获取hash表的字段数量 (integer) 2 ====================================================== 127.0.0.1:6379> hexists myhash field1 #判断hash中指定的 字段是否存在 (integer) 1 127.0.0.1:6379> hexists myhash field3 (integer) 0 ===================================================== # 只获得所有的key # 只获得所有的value 127.0.0.1:6379> hkeys myhash# 只获得所有的key 1) "field2" 2) "field1" 127.0.0.1:6379> hvals myhash# 只获得所有的value 1) "world" 2) "hello" =================================================== #hincrby指定增量 #hsetnx 如果不存在则可以设置 如果存在则设置失败 127.0.0.1:6379> hset myhash field3 5 (integer) 1 127.0.0.1:6379> hincrby myhash field3 1 #指定增量 (integer) 6 127.0.0.1:6379> hincrby myhash field3 -1 (integer) 5 127.0.0.1:6379> hsetnx myhash field4 hello#如果不存在则可以设置 (integer) 1 127.0.0.1:6379> hsetnx myhash field4 world# 如果存在则设置失败 (integer) 0
hash可以存变更的数据 user name age 尤其是用户信息之类经常变动的信息!hash更适合于对象的存储,String更加适合字符串的存储!
127.0.0.1:6379> hset user:1 name qinjiang (integer) 1 127.0.0.1:6379> hget user:1 name "qinjiang
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 3 three #添加多个值 (integer) 2 127.0.0.1:6379> zrange myset 0 -1 1) "one" 2) "two" 3) "three" ============================================== 排序如何实现 #zrevrange 在排序的设置返回的成员范围,通过索引,下令从分数高到低 # zrangebyscore 返回的有序集合中指定分数区间内的成员 分数由低到高 127.0.0.1:6379> zadd salary 2500 xiaoming #添加3个用户 (integer) 1 127.0.0.1:6379> zadd salary 5000 zhangsan (integer) 1 127.0.0.1:6379> zadd salary 500 kuangshen (integer) 1 127.0.0.1:6379> zrangebyscore salary -inf +inf #显示全部的用户,从小到大! 1) "kuangshen" 2) "xiaoming" 3) "zhangsan" 127.0.0.1:6379> zrevrange salary 0 -1 #zrevrange 在排序的设置返回的成员范围,通过索引,下令从分数高到低 1) "zhangsan" 2) "xiaoming" 3) "kuangshen" 127.0.0.1:6379> zrangebyscore salary -inf +inf withscores#显示全部的用户并且附带成绩 1) "kuangshen" 2) "500" 3) "xiaoming" 4) "2500" 5) "zhangsan" 6) "5000" 127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores#显示工资小于2500员工的升序排序 1) "kuangshen" 2) "500" 3) "xiaoming" 4) "2500" ========================================================================== 移除元素 127.0.0.1:6379> zrange salary 0 -1 1) "kuangshen" 2) "xiaoming" 3) "zhangsan" 127.0.0.1:6379> zrem salary xiaoming #移除有序集合中的指定元素 (integer) 1 127.0.0.1:6379> zrange salary 0 -1 1) "kuangshen" 2) "zhangsan" 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 kuangshen (integer) 2 127.0.0.1:6379> zcount myset 1 3 #获取指定区间的成员数量 (integer) 3 127.0.0.1:6379> zcount myset 1 2 (integer) 2 127.0.0.1:6379> zcount myset 2 3 (integer) 2
查看命令的官网地址:Redis命令中心(Redis commands) -- Redis中国用户组(CRUG)
案例思路:set排序 存储班级成绩表 工资表排序
普通消息 1 重要消息 2 带权重进行判断
三种特殊数据类型
geospatial :地理位置
朋友的定位 附近的人 打车计算距离
Redis的Geo在Redis3.2版本就推出了,这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人!
可以查询城市的经纬度的网址:城市经纬度查询-国内城市经度纬度在线查询工具 (jsons.cn)
经纬度查询 - 坐标拾取系统 (bmcx.com)
只有6个命令:
getadd
有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度
官方文档:Redis GEOADD 命令_将指定的地理空间位置(纬度、经度、名称)添加到指定的key中
#getadd 添加地理位置 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 114.05 22.52 shengzhen (error) ERR syntax error 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shengzhen (integer) 2 127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian (integer) 2
Redis GEOPOS 命令 - 从key里返回所有给定位置元素的位置(经度和纬度)
获得当前定位:一定是一个坐标值
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"
Redis GEODIST 命令 - 返回两个给定位置之间的距离
如果两个位置之间的其中一个不存在, 那么命令返回空值。
指定单位的参数 unit 必须是以下单位的其中一个:
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 #查看上海到北京的直线距离 以km为单位 "1067.3788" 127.0.0.1:6379> geodist china:city beijing chongqing km#查看重庆到北京的直线距离以km为单位 "1464.0708"
Redis GEORADIUS 命令 - 以给定的经纬度为中心, 找出某一半径内的元素
附近的人?(获得所有附近的人的地址,定位!)通过半径来查询!
127.0.0.1:6379> georadius china:city 110 30 1000 km # 以110 30 这个经纬度为中心,寻找方圆1000km的城市 1) "chongqing" 2) "xian" 3) "shengzhen" 4) "hangzhou" 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 withdist (error) ERR unsupported unit provided. please use m, km, ft, mi 127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 显示到中心距离的位置 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 # 显示他人的定位信息 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 # 删选出指定的结果 1) 1) "chongqing" 2) "341.9374" 3) 1) "106.49999767541885376" 2) "29.52999957900659211" 127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 2 1) 1) "chongqing" 2) "341.9374" 3) 1) "106.49999767541885376" 2) "29.52999957900659211" 2) 1) "xian" 2) "483.8340" 3) 1) "108.96000176668167114" 2) "34.25999964418929977" 127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 3 1) 1) "chongqing" 2) "341.9374" 3) 1) "106.49999767541885376" 2) "29.52999957900659211" 2) 1) "xian" 2) "483.8340" 3) 1) "108.96000176668167114" 2) "34.25999964418929977"
Redis GEORADIUSBYMEMBER 命令 - 找出位于指定范围内的元素,中心点是由给定的位置元素决定
# 找出位于指定元素周围的其他元素 127.0.0.1:6379> georadiusbymember china:city beijing 500 km 1) "beijing" 127.0.0.1:6379> georadiusbymember china:city beijing 1000 km 1) "beijing" 2) "xian" 127.0.0.1:6379> georadiusbymember china:city chongqing 1000 km 1) "chongqing" 2) "xian"
Redis GEOHASH 命令 - 返回一个或多个位置元素的 Geohash 表示
该命令将返回11个字符的Geohash字符串 它将失去精度,但仍将指向同一地区
# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么距离越近 127.0.0.1:6379> geohash china:city beijing chongqing 1) "wx4fbxxfke0" 2) "wm5xzrybty0"
GEO底层的实现原理其实就是Zset!我们可以使用Zset命令操作geo!
127.0.0.1:6379> zrange china:city 0 -1 # 查看地图中全部的元素 1) "chongqing" 2) "xian" 3) "shengzhen" 4) "hangzhou" 5) "shanghai" 6) "beijing" 127.0.0.1:6379> zrem china:city beijing #移除指定的元素 (integer) 1 127.0.0.1:6379> zrange china:city 0 -1 1) "chongqing" 2) "xian" 3) "shengzhen" 4) "hangzhou" 5) "shanghai"
Hyperloglog
什么是基数
简单来说,基数(cardinality,也译作势),是指一个集合(这里的集合允许存在重复元素)中不同元素的个数。
简介
Redis 2.8.9 版本更新了Hyperloglog 数据结构
Reddis Hyperloglog 是基数统计的算法!
优点:占用的内存是固定的,2^64不同的元素的基数,只需要费12KB内存!如果从内存角度来比较的话Hyperloglog首选!
网页的UV(一个人访问一个网站多次,但是还是算作一个人) PV(Page view, 页面浏览量 )UV( unique visitor 网站独立访客)
传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!这个方式如果保存大量的用户id就会比较麻烦。我们的目的是为了计数,而不是保存用户id
测试使用
127.0.0.1:6379> pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey (integer) 1 127.0.0.1:6379> pfcount mykey#统计mykey元素的基数数量 (integer) 10 127.0.0.1:6379> pfadd mykey2 i o p j k h g v n n (integer) 1 127.0.0.1:6379> pfcount mykey2 #统计mykey2元素的基数数量 不统计重复的 (integer) 9 127.0.0.1:6379> pfmerge mykey3 mykey mykey2# 合并两组 mykey mykey2 => mykey3并集 OK 127.0.0.1:6379> pfcount mykey3 # 查看并集的数量! (integer) 15
如果允许容错,那么一定可以使用Hyperloglog
如果不允许容错,就使用set或者用自己的数据类型即可!
Bitmaps
位存储
Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
用例:
使用bitmap来记录周一到周日的打卡! 0代表未打卡 1 代表打卡
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事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行!
一次性 顺序性 排他性 执行一系列的命令!
Redis事务本质: 一组命令的集合!
Redis事务没有隔离级别的概念!
所有的命令在事务中,并没有被直接执行!只有发起执行命令的时候才会执行! Exec
Redis单条命令保存是保存原子性的,但是事务不保证原子性!
redis的事务:
-
开启事务(multi)
-
命令入队(....)
-
执行事务(exec)
正常执行事务!
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 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 #错误命令 (error) ERR wrong number of arguments for 'set' command 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)> 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/0),如果事务队列中存在语法性错误,那么执行命令的时候,其他命令是可以正常执行的!错误命令抛出异常!
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 # 执行的时候失败 自增是不能增字符串的 只能是数字 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" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3" 127.0.0.1:6379> get k1 "v1"
监控 Watch(面试常问)
悲观锁:
-
很悲观,认为什么时候都会出现问题,无论做什么都会加锁
乐观锁:
-
很乐观,认为无论什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据。
-
获取version
-
更新的时候比较version
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
一旦事务执行成功后,监控就会自动取消掉
测试多线程修改值,使用watch 可以当做redis的乐观锁操作!
注意。在这个过程中不要有编译出错 保证都执行了 不然会报这个错误(error) EXECABORT Transaction discarded because of previous errors.
第一个线程
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)> exec #这一步是执行完线程2之后再来执行 线程2修改了money的值,这个时候,就会导致事务执行失败! (nil)
第二个线程
127.0.0.1:6379> get money "80" 127.0.0.1:6379> set money 1000 OK
解决事务执行失败的方法:如果修改失败,获取最新的值就好 在线程1进行修改
127.0.0.1:6379> unwatch # 如果发现事务执行失败,就先解锁 OK 127.0.0.1:6379> watch money # 获取最新的值,再次监视, 相当于 select version 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# 对比监视的值是否发生了变化,如果没有变化,那么就可以执行成功,如果变化了就执行失败,这里应该是指的线程2没有修改值 1) (integer) 999 2) (integer) 21
B站学习网址:【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
这篇关于第124天学习打卡(Redis Set Hash Zset 三种特殊数据类型 事务 乐观锁)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-02阿里云Redis项目实战入门教程
- 2025-01-02阿里云Redis资料入门详解
- 2024-12-30阿里云Redis教程:新手入门指南
- 2024-12-27阿里云Redis学习入门指南
- 2024-12-27阿里云Redis入门详解:轻松搭建与管理
- 2024-12-27阿里云Redis学习:新手入门指南
- 2024-12-24Redis资料:新手入门快速指南
- 2024-12-24Redis资料:新手入门教程与实践指南
- 2024-12-24Redis资料:新手入门教程与实践指南
- 2024-12-07Redis高并发入门详解