失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Redis五大基本类型三种特殊数据类型事务操作(悲观锁 乐观锁)

Redis五大基本类型三种特殊数据类型事务操作(悲观锁 乐观锁)

时间:2020-05-24 11:47:58

相关推荐

Redis五大基本类型三种特殊数据类型事务操作(悲观锁 乐观锁)

Redis五大基本类型

Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如字符串(strings),散列(hashes),列表(lists),集合(sets),有序集合(sorted sets)与范围查询,bitmaps,hyperloglogs和地理空间(geospatial)索引半径查询。Redis内置了复制(replication),LUA脚本(Lua.scripting),LRU驱动事件(LRU eviction),事务(transactions)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(high availability)。

Redis-key

127.0.0.1:6379> ping # 测试是否连接成功PONG127.0.0.1:6379> keys *# 查看所有的key(empty list or set)127.0.0.1:6379> set name yangjian# set keyOK127.0.0.1:6379> keys *1) "name"127.0.0.1:6379> set age 1 # set ageOK127.0.0.1:6379> keys *1) "age"2) "name"127.0.0.1:6379> EXISTS name# 判断当前的key是否存在(integer) 1127.0.0.1:6379> EXISTS name1(integer) 0127.0.0.1:6379> move name 1# 移除当前的key(integer) 1127.0.0.1:6379> keys *1) "age"127.0.0.1:6379> set name yangcheOK127.0.0.1:6379> keys *1) "age"2) "name"127.0.0.1:6379> get name"yangche"127.0.0.1:6379> EXPIRE name 10# 设置key的过期时间,单位是秒(integer) 1127.0.0.1:6379> ttl name# 查看当前key的剩余时间(integer) 4127.0.0.1:6379> ttl name(integer) -2127.0.0.1:6379> get name(nil)127.0.0.1:6379> keys *1) "age"2) "name"127.0.0.1:6379> type name# 查看当前key的一个类型!string127.0.0.1:6379> type agestring127.0.0.1:6379>

String(字符串)

###################################################################################127.0.0.1:6379> set key1 v1# 设置值OK127.0.0.1:6379> get key1# 获得值"v1"127.0.0.1:6379> keys *# 获得所有的key1) "key1"127.0.0.1:6379> EXISTS key1# 判断某一个key是否存在(integer) 1127.0.0.1:6379> APPEND key1 "hello"# 追加字符串,如果当前key不存在,就相当于setkey(integer) 7127.0.0.1:6379> get key1"v1hello"127.0.0.1:6379> STRLEN key1# 获取字符串的长度(integer) 7127.0.0.1:6379> APPEND key1 "yangjian"(integer) 15127.0.0.1:6379> STRLEN key1(integer) 15127.0.0.1:6379> get key1"v1helloyangjian"127.0.0.1:6379>################################################################################### i++# 步长 i+=127.0.0.1:6379> set views 0# 初始浏览量为0OK127.0.0.1:6379> get views"0"127.0.0.1:6379> incr views# 自增1 浏览量变为1(integer) 1127.0.0.1:6379> incr views(integer) 2127.0.0.1:6379> get views"2"127.0.0.1:6379> decr views# 自减1 浏览量变为1(integer) 1127.0.0.1:6379> decr views(integer) 0127.0.0.1:6379> decr views(integer) -1127.0.0.1:6379> get views"-1"127.0.0.1:6379> INCRBY views 10# 可以设置步长 指定增量(integer) 9127.0.0.1:6379> INCRBY views 10(integer) 19127.0.0.1:6379> DECRBY views 5# 可以设置步长,指定减量(integer) 14127.0.0.1:6379> #################################################################################### 字符串范围 range127.0.0.1:6379> set key1 "hello,yangjian"# 设置key1的值OK127.0.0.1:6379> get key1"hello,yangjian"127.0.0.1:6379> GETRANGE key1 0 3# 截取字符串 [0,3]"hell"127.0.0.1:6379> GETRANGE key1 0 -1# 获取全部字符串 和 get key是一样的"hello,yangjian"127.0.0.1:6379> # 替换!127.0.0.1:6379> set key2 abcdefgOK127.0.0.1:6379> get key2"abcdefg"127.0.0.1:6379> SETRANGE key2 1 xx# 替换指定位置开始的字符串!(integer) 7127.0.0.1:6379> get key2"axxdefg"127.0.0.1:6379> #################################################################################### setex(set with expire)# 设置过期时间# setnx(set if not exist)# 不存在设置(在分布式锁中会常常使用!)127.0.0.1:6379> setex key3 30 "hello"# 设置key3 的值为hello,30秒后过期OK127.0.0.1:6379> ttl key3(integer) 24127.0.0.1:6379> get key3"hello"127.0.0.1:6379> ttl key3(integer) 8127.0.0.1:6379> get keys(nil)127.0.0.1:6379> setnx mykey "redis"# 如果mykey不存在,创建mykey(integer) 1127.0.0.1:6379> keys *1) "mykey"2) "key2"3) "key1"127.0.0.1:6379> ttl key3(integer) -2127.0.0.1:6379> setnx mykey "MongoDB"# 如果mykey存在,创建失败(integer) 0127.0.0.1:6379> get mykey"redis"127.0.0.1:6379> ##################################################################################### mset## mget127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3# 同时设置多个值OK127.0.0.1:6379> keys *1) "k2"2) "k3"3) "k1"127.0.0.1:6379> mget k1 k2 k3# 同时获取多个值1) "v1"2) "v2"3) "v3"127.0.0.1:6379> msetnx k1 v1 k4 v4# msetnx是一个原子性的操作,要么一起成功,要么一起失败!(integer) 0127.0.0.1:6379> get k4(nil)127.0.0.1:6379> # 对象set user:1 {name:zhangsan,age:3}# 设置一个user:1对象 值为json字符来保存一个对象!# 这里的key是一个巧妙地设计:user:{id}:{filed},如此设计在Redis中是完全可以了。127.0.0.1:6379> mset user:1:name zhangsan user:1:age 23OK127.0.0.1:6379> mget user:1:name user:1:age1) "zhangsan"2) "23" #################################################################################### getset先get 然后再 set127.0.0.1:6379> getset bd redis# 如果不存在值,则返回nil(nil)127.0.0.1:6379> get bd"redis"127.0.0.1:6379> getset bd mongibd# 如果存在值,获取原来的值,并设置新的值"redis"127.0.0.1:6379> get bd"mongibd"127.0.0.1:6379> ###################################################################################

数据结构都是相通的!

String类似的使用场景:value除了是我们的字符串还可以是我们的数字

计数器统计获取多单位的数量粉丝数对象缓存对象

List(列表)

基本的数据类型,列表

在redis里面,我们可以把list玩成栈,队列,阻塞队列。

所有的list命令都是l开头的,Redis不区分大小写命令。

###################################################################################127.0.0.1:6379> LPUSH list one# 将一个值或者多个值,插入到头部(integer) 1127.0.0.1:6379> LPUSH list two(integer) 2127.0.0.1:6379> LPUSH list three(integer) 3127.0.0.1:6379> LRANGE list 0 -1# 获取list中的值1) "three"2) "two"3) "one"127.0.0.1:6379> LRANGE list 0 1# 通过区间获取具体的值1) "three"2) "two"127.0.0.1:6379> RPUSH list right# 将一个值或者多个值,插入到列表尾部(右)(integer) 4127.0.0.1:6379> LRANGE list 0 -11) "three"2) "two"3) "one"4) "right"127.0.0.1:6379> ###################################################################################LPOPRPOP127.0.0.1:6379> LRANGE list 0 -11) "three"2) "two"3) "one"4) "right"127.0.0.1:6379> Lpop list# 移除列表的第一个元素"three"127.0.0.1:6379> Rpop list# 移除列表的最后一个元素"right"127.0.0.1:6379> LRANGE list 0 -11) "two"2) "one"###################################################################################Lindex127.0.0.1:6379> LRANGE list 0 -11) "two"2) "one"127.0.0.1:6379> Lindex list 1# 通过下标获得list中的某一个值!"one"127.0.0.1:6379> Lindex list 0"two"###################################################################################Llen127.0.0.1:6379> Lpush list one(integer) 1127.0.0.1:6379> Lpush list two(integer) 2127.0.0.1:6379> Lpush list three(integer) 3127.0.0.1:6379> LRANGE list 0 -11) "three"2) "two"3) "one"127.0.0.1:6379> Llen list# 返回列表的长度(integer) 3127.0.0.1:6379> #################################################################################### 移除指定的值!Lrem127.0.0.1:6379> Lrange list 0 -11) "three"2) "three"3) "two"4) "one"127.0.0.1:6379> lrem list 1 three# 移除list 集合中指定个数的value,精确匹配(integer) 1127.0.0.1:6379> Lrange list 0 -11) "three"2) "two"3) "one"127.0.0.1:6379> Lpush list three(integer) 4127.0.0.1:6379> Lrange list 0 -11) "three"2) "three"3) "two"4) "one"127.0.0.1:6379> lrem list 2 three(integer) 2127.0.0.1:6379> Lrange list 0 -11) "two"2) "one"###################################################################################trim 修剪 127.0.0.1:6379> Rpush list "hello1"(integer) 1127.0.0.1:6379> Rpush list "hello2"(integer) 2127.0.0.1:6379> Rpush list "hello3"(integer) 3127.0.0.1:6379> Rpush list "hello4"(integer) 4127.0.0.1:6379> Lrange list 0 -11) "hello1"2) "hello2"3) "hello3"4) "hello4"127.0.0.1:6379> ltrim list 1 2# 通过下标截取指定的长度,这个list已经被改变了,截断了只剩下截取的元素OK127.0.0.1:6379> Lrange list 0 -11) "hello2"2) "hello3"127.0.0.1:6379> #################################################################################### rpoplpush 移除列表的最后一个元素,并移动到新的列表中127.0.0.1:6379> rpush list "hello"(integer) 1127.0.0.1:6379> rpush list "hello1"(integer) 2127.0.0.1:6379> rpush list "hello2"(integer) 3127.0.0.1:6379> rpoplpush list otherlist# 移除列表的最后一个元素,将他移动到新的列表中"hello2"127.0.0.1:6379> lrange list 0 -1# 查看原来的列表1) "hello"2) "hello1"127.0.0.1:6379> lrange otherlist 0 -1# 查看目标列表中,确实存在该值。1) "hello2"#################################################################################### lset 将列表中指定下标的值替换成另一个值,更新操作127.0.0.1:6379> EXISTS list# 判断这个列表是否存在(integer) 0127.0.0.1:6379> lset list 0 item# 如果不存在列表,我们去更新就会报错(error) ERR no such key127.0.0.1:6379> lpush list value1(integer) 1127.0.0.1:6379> lrange list 0 01) "value1"127.0.0.1:6379> lset list 0 item# 如果存在,更新当前的操作OK127.0.0.1:6379> lrange list 0 01) "item"127.0.0.1:6379> lset list 1 other# 如果不存在,则会报错(error) ERR index out of range#################################################################################### linsert将某一个具体的value插入到列表中某个元素的前面或者后面127.0.0.1:6379> Rpush list hello(integer) 1127.0.0.1:6379> Rpush list world(integer) 2127.0.0.1:6379> LINSERT list before world other(integer) 3127.0.0.1:6379> Lrange list 0 -11) "hello"2) "other"3) "world"127.0.0.1:6379> LINSERT list after world new(integer) 4127.0.0.1:6379> lrange list 0 -11) "hello"2) "other"3) "world"4) "new"

总结:

list实际上是一个链表,before Node after , left ,right 都可以插入值如果key不存在,创建新的链表如果key存在,新增内容如果移除了所有值,空链表,也代表不存在。在两边插入或者改动值,效率最高,中间元素,相对来说效率会低一些。

消息排队!消息队列(Lpush Rpop),栈(Lpush Lpop)

Set(集合)

set中的值是不能重复的。

##################################################################################127.0.0.1:6379> sadd set "hello"# set集合中添加元素(integer) 1127.0.0.1:6379> sadd set "yangjian"(integer) 1127.0.0.1:6379> sadd set "study hard"(integer) 1127.0.0.1:6379> SMEMBERS set# 查看指定set的所有值1) "study hard"2) "yangjian"3) "hello"127.0.0.1:6379> SISMEMBER set hello# 判断某一个值是不是在set集合中!(integer) 1127.0.0.1:6379> SISMEMBER set yangche(integer) 0##################################################################################127.0.0.1:6379> scard set# 获取set集合中的内容元素个数(integer) 4################################################################################### srem127.0.0.1:6379> srem set hello# 移除set集合中的指定元素(integer) 1127.0.0.1:6379> scard set(integer) 3127.0.0.1:6379> SMEMBERS set1) "yangjian2"2) "study hard"3) "yangjian"##################################################################################set 无序不重复集合,抽随机:127.0.0.1:6379> SMEMBERS set# 随机抽选出其中的一个元素1) "yangjian2"2) "study hard"3) "yangjian"127.0.0.1:6379> SRANDMEMBER set"yangjian2" 127.0.0.1:6379> SRANDMEMBER set 2# 随机抽选出指定个数的元素1) "yangjian"2) "study hard"127.0.0.1:6379> SRANDMEMBER set 2# 随机抽选出指定个数的元素1) "yangjian"2) "study hard"127.0.0.1:6379> SRANDMEMBER set 2# 随机抽选出指定个数的元素1) "yangjian"2) "yangjian2"127.0.0.1:6379> 127.0.0.1:6379> SRANDMEMBER set# 随机抽选出其中的一个元素"study hard"127.0.0.1:6379> ##################################################################################删除指定的key,随即删除key127.0.0.1:6379> SMEMBERS set1) "yangjian2"2) "study hard"3) "yangjian"127.0.0.1:6379> spop set# 随机删除一些set集合中的元素"study hard"127.0.0.1:6379> spop set"yangjian2"127.0.0.1:6379> SMEMBERS set1) "yangjian"################################################################################### 将一个指定的值,移动到另一个set集合中127.0.0.1:6379> sadd set "yangjian"(integer) 1127.0.0.1:6379> sadd set "hello"(integer) 1127.0.0.1:6379> sadd set "world"(integer) 1127.0.0.1:6379> SMEMBERS set1) "hello"2) "yangjian"3) "world"127.0.0.1:6379> sadd set2 "yangjian2"(integer) 1127.0.0.1:6379> smove set set2 yangjian# 将一个指定的值,移动到另一个set集合中(integer) 1127.0.0.1:6379> SMEMBERS set1) "hello"2) "world"127.0.0.1:6379> SMEMBERS set21) "yangjian"2) "yangjian2"##################################################################################微博:B站:共同关注!(并集)数字集合类:-差集:SDIFF-交集:SINTER-并集:SUNION127.0.0.1:6379> sadd key1 a(integer) 1127.0.0.1:6379> sadd key1 b(integer) 1127.0.0.1:6379> sadd key1 c(integer) 1127.0.0.1:6379> sadd key2 c(integer) 1127.0.0.1:6379> sadd key2 d(integer) 1127.0.0.1:6379> sadd key2 e(integer) 1127.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) "c"2) "b"3) "a"4) "e"5) "d"

微博,A用户将所有的关注的人放在一个set集合中!将它的粉丝也放在一个集合中!

共同关注,共同爱好,二度好友,推荐好友!(六度分隔理论)

Hash(哈希)

Map集合,key-map!这个值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-value!

##################################################################################127.0.0.1:6379> hset hash field1 yangjian# set一个具体 key-value(integer) 1127.0.0.1:6379> hget hash field1"yangjian"127.0.0.1:6379> hmset hash field1 hello field2 world# set 多个key-valueOK127.0.0.1:6379> hmget hash field1 field2# 获取多个字段值1) "hello"2) "world"127.0.0.1:6379> hgetall hash# 获取全部的数据1) "field1"2) "hello"3) "field2"4) "world"127.0.0.1:6379> hdel hash field1# 删除hash指定key字段!对应的value值也就消失了!(integer) 1127.0.0.1:6379> hgetall hash1) "field2"2) "world"##################################################################################hlen127.0.0.1:6379> hmset hash field1 hello field2 worldOK127.0.0.1:6379> hgetall(error) ERR wrong number of arguments for 'hgetall' command127.0.0.1:6379> HGETALL hash1) "field1"2) "hello"3) "field2"4) "world"127.0.0.1:6379> hlen hash# 获取hash表的字段数量(integer) 2##################################################################################127.0.0.1:6379> HEXISTS hash field1# 判断hash中指定的字段是否存在(integer) 1127.0.0.1:6379> HEXISTS hash field3(integer) 0################################################################################### 只获得所有的field字段# 只获得所有的value值127.0.0.1:6379> hkeys hash# 只获得所有的field字段1) "field1"2) "field2"127.0.0.1:6379> hvals hash# 只获得所有的value值1) "hello"2) "world"################################################################################### incr decr127.0.0.1:6379> hset hash field3 5# 指定增量(integer) 1127.0.0.1:6379> HINCRBY hash field3 1(integer) 6127.0.0.1:6379> HINCRBY hash field3 -1(integer) 5127.0.0.1:6379> hsetnx hash field4 hello# 如果不存在则可以设值(integer) 1127.0.0.1:6379> hsetnx hash field4 world# 如果存在则不可以设值(integer) 0

hash变更的数据 user name age ,尤其是用户信息之类的,经常变动的信息!hash更适合于对象的存储,String更加适合字符串存储!

Zset(有序集合)

在set的基础上,增加了一个值,set k1 v1 zset k1 score1 v1

##################################################################################127.0.0.1:6379> zadd set 1 one# (integer) 1127.0.0.1:6379> zadd set 2 two 3 three(integer) 2127.0.0.1:6379> zrange set 0 -11) "one"2) "two"3) "three"##################################################################################排序如何实现127.0.0.1:6379> zadd salary 2500 xiaohong# 添加三个用户(integer) 1127.0.0.1:6379> zadd salary 5000 zhangsan(integer) 1127.0.0.1:6379> zadd salary 500 yangjian(integer) 1127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf# 显示全部的用户,从小到大的排序1) "yangjian"2) "xiaohong"3) "zhangsan"127.0.0.1:6379> zrevrange salary 0 -1# 从大到小进行排序1) "zhangsan"2) "yangjian"127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores# 显示所有的用户 并且附带成绩1) "yangjian"2) "500"3) "xiaohong"4) "2500"5) "zhangsan"6) "5000"127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores# 显示工资小于2500员工的升序排列1) "yangjian"2) "500"3) "xiaohong"4) "2500"##################################################################################移除rem中的元素127.0.0.1:6379> zadd salary 2500 xiaohong(integer) 1127.0.0.1:6379> zadd salary 5000 zhangsan(integer) 1127.0.0.1:6379> zadd salary 500 yangjian(integer) 1127.0.0.1:6379> zrem salary xiaohong# 移除有序集合中的指定元素(integer) 1127.0.0.1:6379> zrange salary 0 -11) "yangjian"2) "zhangsan"127.0.0.1:6379> zcard salary# 获取有序集合中的个数(integer) 2##################################################################################127.0.0.1:6379> zadd set 1 hello(integer) 1127.0.0.1:6379> zadd set 2 world 3 yangjian(integer) 2127.0.0.1:6379> zcount set 1 3# 获取指定区间的成员数量(integer) 3127.0.0.1:6379> zcount set 1 2(integer) 2

其余的一些API,通过我们的学习,剩下的一些API可以去查看官方文档。

案例思路:set 排序 存储班级成绩表,工资表排序!

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

案例应用:排行榜应用实现。

三种特殊数据类型:

geospatial 地理位置

朋友圈的定位,附近的人,打车距离计算

Redis的Geo

getadd

# getadd 添加地理位置# 规则:两级无法直接添加,我们一般会下载城市数据,直接通过Java程序一次性导入!# 参数 key 值(纬度,经度,位置)# 有效的经度从-180度到180度# 有效的纬度从-85度到+85度# 当坐标位置超出上述指定范围时,该命令将会返回一个错误。127.0.0.1:6379> geoadd china:city 116.40 39.9 beijing(integer) 1127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai(integer) 1127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 14.05 22.52 shenzhen(integer) 2127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian(integer) 2

geopos

获得当前定位,一定是一个坐标值。

127.0.0.1:6379> geopos china:city shanghai# 获取指定的城市的经度和纬度1) 1) "121.47000163793564"2) "31.229999039757836"127.0.0.1:6379> geopos china:city beijing1) 1) "116.39999896287918"2) "39.900000091670925"127.0.0.1:6379> geopos china:city chongqing1) 1) "106.49999767541885"2) "29.529999579006592"127.0.0.1:6379> geopos china:city xian1) 1) "108.96000176668167"2) "34.2599996441893"

getdist

两人之间的距离!

单位:

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# 查看北京到西安的距离"910.0565"127.0.0.1:6379> geodist china:city xian shanghai km# 查看西安到上海的距离"1216.9307"

GEORADIUS:

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

获得指定数量的人,200

所有数据应该都录入:china:city,才会让结果更加清晰。

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 km1) "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) "483.8340"127.0.0.1:6379> georadius china:city 110 30 500 km withcoord# 显示到他人的定位信息1) 1) "chongqing"2) 1) "106.49999767541885"2) "29.529999579006592"2) 1) "xian"2) 1) "108.96000176668167"2) "34.2599996441893"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.49999767541885"2) "29.529999579006592"127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 21) 1) "chongqing"2) "341.9374"3) 1) "106.49999767541885"2) "29.529999579006592"2) 1) "xian"2) "483.8340"3) 1) "108.96000176668167"2) "34.2599996441893"

GEORADIUSBYMEMBER:

# 找出位于指定元素周围的其他元素127.0.0.1:6379> georadiusbymember china:city beijing 1000 km1) "beijing"2) "xian"127.0.0.1:6379> georadiusbymember china:city shanghai 400 km1) "hangzhou"2) "shanghai"

GEOHASH:该命令返回一个或多个位置元素的Geohash表示

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

# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么距离则越近。127.0.0.1:6379> geohash china:city beijing chongqing1) "wx4fbxxfke0"2) "wm5xzrybty0"

GEO底层的实现原理其实就是Zset,我们可以使用Zset命令来操作geo

127.0.0.1:6379> ZRANGE china:city 0 -1# 查看地图中全部的元素1) "shenzhen"2) "chongqing"3) "xian"4) "hangzhou"5) "shanghai"6) "beijing"127.0.0.1:6379> zrem china:city beijing# 移除指定的元素(integer) 1127.0.0.1:6379> ZRANGE china:city 0 -11) "shenzhen"2) "chongqing"3) "xian"4) "hangzhou"5) "shanghai"

Hyperloglog

什么是基数?

A:{1,3,5,7,8,7}

B:{1,3,5,7,8}

基数(不重复元素)= 5,可以接受误差!

Redis 2.8.9版本就更新了Hyperloglog数据结构!

Redis Hyperloglog基数统计的算法!

优点:占用的内存是固定,2^64不同的元素的技术,只需要用12KB的内存!如果要从内存角度来比较的话,Hyperloglog首选!

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

传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!

这个方式如果保存大量的用户id,就会比较麻烦,我们的目的是为了计数,而不是保存用户id

0.81%的错误率!统计UV任务,可以忽略不计的!

# 测试使用127.0.0.1:6379> PFadd mykey a b c d e f g h i j# 创建第一组元素 mykey(integer) 1127.0.0.1:6379> PFCOUNT mykey# 统计mykey元素的基数数量(integer) 10127.0.0.1:6379> PFadd mykey2 i j z x c v b n m# 创建第二组元素 mykey2(integer) 1127.0.0.1:6379> PFCOUNT mykey2(integer) 9127.0.0.1:6379> PFMERGE mykey3 mykey mykey2# 合并两组,mykey mykey2 => mykey3 并集OK127.0.0.1:6379> PFCOUNT mykey3# 看并集的数量!(integer) 15

如果允许容错,那么一定可以使用Hyperloglog!

如果不允许容错,就使用set或者自己的数据类型即可!

Bitmaps

位存储

统计用户信息,活跃,不活跃! 登录,未登陆!打卡,365打卡!两个状态的,都可以使用Bitmaps!

Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!

365天=365bit 1字节=8bit 46个字节左右!

使用bitmap来记录 周一到周日的打卡!

周一:1 周二:0 周三:0 周四:1

127.0.0.1:6379> setbit sign 0 1(integer) 0127.0.0.1:6379> setbit sign 1 0(integer) 0127.0.0.1:6379> setbit sign 2 0(integer) 0127.0.0.1:6379> setbit sign 3 1(integer) 0127.0.0.1:6379> setbit sign 4 1(integer) 0127.0.0.1:6379> setbit sign 5 0(integer) 0127.0.0.1:6379> setbit sign 6 0(integer) 0

查看某一天是否打卡?

127.0.0.1:6379> getbit sign 3(integer) 1127.0.0.1:6379> getbit sign 6(integer) 0

统计操作,统计打卡的天数!

127.0.0.1:6379> bitcount sign# 统计这周的打卡记录,就可以看到是否有全勤!(integer) 3

Redis事务操作

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

一次性,顺序性,排他性,执行一些列的命令!

----- 队列 set set set 执行 -----

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

所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!Exec

Redis要么单条命令是保证原子性的,但是事务不保证原子性

Redis的事务:

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

############################################################################# 正常执行事务!127.0.0.1:6379> multi# 开启事务OK# 命令入队127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> get k2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> exec# 执行事务1) OK2) OK3) "v2"4) OK############################################################################放弃事务!127.0.0.1:6379> multi# 开启事务OK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> DISCARD# 取消事务OK127.0.0.1:6379> get k4# 事务队列中命令都不会被执行(nil)############################################################################编译型异常(代码有问题!命令有错!),事务中所有的命令都不会执行!127.0.0.1:6379> multiOK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> getset k3# 错误的命令(error) ERR wrong number of arguments for 'getset' command127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> set k5 v5QUEUED127.0.0.1:6379> exec# 执行事务报错(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get k5# 所有的命令都不会被执行(nil)127.0.0.1:6379> get k4# 所有的命令都不会被执行(nil)############################################################################# 运行时异常(1/0),如果事务队列中存在语法错误,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!127.0.0.1:6379> set k1 "v1"OK127.0.0.1:6379> multiOK127.0.0.1:6379> incr k1# 在执行的时候失败QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> get k3QUEUED127.0.0.1:6379> exec1) (error) ERR value is not an integer or out of range# 虽然第一条命令报错了,但是依然执行成功了2) OK3) OK4) "v3"127.0.0.1:6379> get k2"v2"127.0.0.1:6379> get k3"v3"

监控!Watch(面试常问)

悲观锁

很悲观,认为什么时候都会出问题,无论做什么都会加锁!

乐观锁

很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据。获取version更新的时候比较version

Redis 监控测试

正常执行成功!

127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money# 监视moneyOK127.0.0.1:6379> multi# 事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!OK127.0.0.1:6379> DECRBY money 20QUEUED127.0.0.1:6379> INCRBY out 20QUEUED127.0.0.1:6379> exec1) (integer) 802) (integer) 20

测试多线程修改值,使用watch,可以当作redis的乐观锁操作!

127.0.0.1:6379> watch money# 监视moneyOK127.0.0.1:6379> multiOK127.0.0.1:6379> DECRBY money 10QUEUED127.0.0.1:6379> INCRBY out 10QUEUED127.0.0.1:6379> exec# 执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败。(nil)

如果修改失败,获取最新的值就好!

如果觉得《Redis五大基本类型三种特殊数据类型事务操作(悲观锁 乐观锁)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。