Skip to content

基础知识

redis默认有16个数据库,默认使用的数据库索引为0,切换数据库可以使用select,DBSIZE可以查看数据库大小

keys *查看数据库所有key

清除当前数据库 flushdb,清除全部数据库的内容flushall

redis是单线程的,官方表示,Redis是基于内存操作的

基础命令学习地图

Redis 基础命令不要按字母背,而要按“数据结构能解决什么问题”来学。

mermaid
flowchart TD
    A["Key 通用命令<br/>exists / expire / ttl / type"] --> B["String<br/>缓存 / 计数器 / 锁"]
    B --> C["Hash<br/>对象字段 / 购物车"]
    C --> D["List<br/>队列 / 时间线"]
    D --> E["Set<br/>去重 / 标签 / 共同好友"]
    E --> F["ZSet<br/>排行榜 / 延迟任务"]
    F --> G["事务和脚本<br/>multi / exec / lua"]

为什么要先学 Key 通用命令:Redis 的所有数据结构都挂在 key 上,过期时间、类型判断、删除策略都围绕 key 展开。如果不会 ttltypeexists,排查缓存不命中、类型错误、大量 key 堆积时会很被动。

如果把 Redis 当成普通 Map 使用,容易出现三个问题:

  1. Key 没有业务前缀,后期很难定位来源。
  2. 不设置过期时间,内存被长期占用。
  3. 不区分数据结构,导致命令复杂度过高。

五大基本数据类型

redis-key

redis中key区分大小写

bash
redis-cli -p 6379	#连接redis

EXISTS [KEY] 判断当前的key是否存在

move [key] 1移除当前的key

EXPIRE [KEY] X 设置当前key过期时间,单位:X秒,类似cookie

ttl [key] 查看当前key的过期时间

type [key]查看key对应value的类型

APPEND [KEY] "*" 追加字符串如多当前key不存在就相当于set key

bash
127.0.0.1:6379> keys *
1) "k2"
2) "mysay"
3) "views"
4) "k1"
5) "k3"
6) "say2"
7) "say"
127.0.0.1:6379> flushdb	#清空数据库
OK
127.0.0.1:6379> keys *
(empty array)

增长

bash
#i++操作
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> incr views 	#自增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> incr views
(integer) 3
127.0.0.1:6379> decr views	#自减1
(integer) 2
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> incrby views 10	#设置步长
(integer) 11
127.0.0.1:6379> decrby views 5
(integer) 6

String

bash
#字符范围 rang
127.0.0.1:6379> set say "hello,redis"
OK
127.0.0.1:6379> get say
"hello,redis"
127.0.0.1:6379> GETRANGE say 0 3 #截取字符串[0,3]
"hell"
127.0.0.1:6379> GETRANGE say 0 -1 #截取全部字符串
"hello,redis"
bash
127.0.0.1:6379> set say2 qwertyu
OK
127.0.0.1:6379> get say2
"qwertyu"
127.0.0.1:6379> setrange say2 1 aa	#替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get say2
"qaartyu"
127.0.0.1:6379> setrange say2 0 xx
(integer) 7
127.0.0.1:6379> get say2
"xxartyu"




#####################################################################################
#	setex (set with expire) 设置过期时间
#	setnx (set if not exist) 不存在设置(分布式锁中会常常用)

127.0.0.1:6379> setex say3 30 "hello"	#设置say3 的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl say3	#查看剩余过期秒数
(integer) 20
127.0.0.1:6379> ttl say3
(integer) 17
127.0.0.1:6379> get say3
"hello"
127.0.0.1:6379> get say3
"hello"
127.0.0.1:6379> ttl say3
(integer) 4
127.0.0.1:6379> setnx mysay "redis"	#如果mysay不存在,创建mysay
(integer) 1	#1表示成功
127.0.0.1:6379> keys *
1) "say2"
2) "mysay"
3) "views"
4) "say"
127.0.0.1:6379> setnx mysay "MongoDB"	#如果mysay存在,创建失败!
(integer) 0	#0表示失败
127.0.0.1:6379> get mysay
"redis"
###################################################################################

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3	#同时设置多个键值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
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) 0
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"

#####################################################################################

set user:1{name:zhangsan,age:12} #设置一个user:1对象 值为json字符来保存一个对象

#这里的key是一个巧妙的设计:user:{id}:{filed}

127.0.0.1:6379> mset user:1:name zhangsan user:1:age 12
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "12"

#####################################################################################
getset	#先get后set

127.0.0.1:6379> getset db mongodb	#如果不存在值,则返回nil,设置值
(nil)
127.0.0.1:6379> get db
"mongodb"
127.0.0.1:6379> getset db redis	#如果存在值,则返回值,设置新值
"mongodb"
127.0.0.1:6379> get db
"redis"


#####################################################################################

List

在redis中,我们可以将list玩成栈、队列、阻塞队列

所有的list命令都是用l开头的

bash
#####################################################################################

127.0.0.1:6379> lpush list one	#将一个值或者多个值插入到列表的头部(上,左)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.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) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"

#####################################################################################

lpop
rpop

127.0.0.1:6379> lpop list	#移除队首的第一个
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> rpop list	#移除队尾的第一个
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

#####################################################################################
lindex

127.0.0.1:6379> lindex list 0	#通过下标获取某一个值
"two"
127.0.0.1:6379> lindex list 1	
"one"

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> llen list	#返回列表的长度
(integer) 2

#####################################################################################

移除指定的值

    127.0.0.1:6379> lrange list 0 -1	#将list中的值全部取出
1) "two"
2) "one"
127.0.0.1:6379> llen list	#查看list长度
(integer) 2
127.0.0.1:6379> lpush list three	#向list中添加值
(integer) 3
127.0.0.1:6379> lpush list three
(integer) 4
    127.0.0.1:6379> lrange list 0 -1	#将list中的值全部取出
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 three	#从list中移除一个值从上至下,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpush list three
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 2 three	#从list中移除两个值从上至下
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

#####################################################################################
截取
127.0.0.1:6379> lpush mylist "hello" "redis" "MongoDB"
(integer) 3
127.0.0.1:6379> keys *
1) "mylist"
127.0.0.1:6379> lrange mylist 0 -1
1) "MongoDB"
2) "redis"
3) "hello"
127.0.0.1:6379> ltrim mylist 1 2	#通过下标截取指定区间长度的值,该list集合只剩下截取的元素
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "redis"
2) "hello"

#####################################################################################

LSET

127.0.0.1:6379> lpush mylist "hello" "redis" "MongoDB"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "MongoDB"
2) "redis"
3) "hello"
#组合
rpoplpush [list] [list]
rpoprpush [list] [list] 
lpoplpush [list] [list] 
lpoprpush [list] [list]

127.0.0.1:6379> rpoplpush mylist otherlist	#从mylist中移除值到otherlist(如果otherlist不存在则创建)
"hello"
127.0.0.1:6379> lrange mylist 0 -1	
1) "MongoDB"
2) "redis"
127.0.0.1:6379> lrange otherlist 0 -1
1) "hello"
127.0.0.1:6379> keys *
1) "mylist"
2) "otherlist"
127.0.0.1:6379> lset test 0 hello	#list将下标为0 的值设置为hello,如果list集合不存在则报错
(error) ERR no such key
127.0.0.1:6379> lset otherlist 0 xiaomi	#list将下标为X 的值设置为*,如果list集合存在则将原有值设置为*相当于更新操作
OK
127.0.0.1:6379> lrange otherlist 0 -1
1) "xiaomi"
127.0.0.1:6379> llen otherlist
(integer) 1
127.0.0.1:6379> lset otherlist 1 xiaomi
(error) ERR index out of range

#####################################################################################
#插入
linsert

127.0.0.1:6379>  LRANGE mylist 0 -1	#将mylist中的值全部取出
1) "MongoDB"
2) "redis"
127.0.0.1:6379> linsert mylist before redis hello	#在redis前插入hello
(integer) 3
127.0.0.1:6379>  LRANGE mylist 0 -1	#将mylist中的值全部取出
1) "MongoDB"
2) "hello"
3) "redis"
127.0.0.1:6379> linsert mylist after mongodb nb	#在MongoDB后插入nb,注意区分字段大小写
(integer) -1
127.0.0.1:6379>  LRANGE mylist 0 -1
1) "MongoDB"
2) "hello"
3) "redis"
127.0.0.1:6379> linsert mylist after MongoDB nb
(integer) 4
127.0.0.1:6379>  LRANGE mylist 0 -1
1) "MongoDB"
2) "nb"
3) "hello"
4) "redis"
127.0.0.1:6379> lpush mylist hello	#向集合中添加hello使得集合中有两个相同的值测试插入时插入到哪一值前或后
(integer) 5
127.0.0.1:6379> linsert mylist after hello lpx	#向hello后插入lpx
(integer) 6
127.0.0.1:6379>  LRANGE mylist 0 -1	#有两个相同value时使用linsert插入时选择的是顶端的value
1) "hello"
2) "lpx"
3) "MongoDB"
4) "nb"
5) "hello"
6) "redis"


#####################################################################################

小结

本质是一个链表,Node前后都可以插入,两边插入的效率比中间高一些。 应用场景:实现消息队列(左进右出,或反之)、栈(左进左出,或反之)。

set

bash
#####################################################################################

127.0.0.1:6379> sadd myset hello redis MongoDB
(integer) 3
127.0.0.1:6379> smembers myset	#查看指定set的所有值
1) "hello"
2) "MongoDB"
3) "redis"
127.0.0.1:6379> sismember myset hello	#判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> sismember myset word
(integer) 0

#####################################################################################

127.0.0.1:6379> scard myset
(integer) 3

#####################################################################################

127.0.0.1:6379> sadd myset lpx	
(integer) 1
127.0.0.1:6379> smembers myset
1) "lpx"
2) "hello"
3) "MongoDB"
4) "redis"
127.0.0.1:6379> srem myset lpx	#移除set集合中指定的元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "hello"
2) "MongoDB"
3) "redis"

#####################################################################################

set无序不重复集合

127.0.0.1:6379> srandmember myset	#随机抽选出一个元素
"redis"
127.0.0.1:6379> srandmember myset
"hello"
127.0.0.1:6379> srandmember myset 2	#随机抽选出两个个元素
1) "hello"
2) "MongoDB"
127.0.0.1:6379> srandmember myset 2
1) "redis"
2) "MongoDB"
127.0.0.1:6379> srandmember myset 2
1) "hello"
2) "MongoDB"
127.0.0.1:6379> srandmember myset 2
1) "hello"
2) "redis"

######################################################################################

删除指定key,随机y

127.0.0.1:6379> smembers myset
1) "hello"
2) "MongoDB"
3) "redis"
127.0.0.1:6379> spop myset	#随机删除set集合中的一些元素
"MongoDB"
127.0.0.1:6379> smembers myset
1) "hello"
2) "redis"
######################################################################################

移动
127.0.0.1:6379> smembers myset
1) "hello"
2) "redis"
127.0.0.1:6379> smove myset myset2 hello	#将一个集合中的元素移动到另一个集合中
(integer) 1
127.0.0.1:6379> smembers myset2
1) "hello"

######################################################################################

微博,B站,共同关注!(并集)
数字集合类
-差集
-交集
-并集

127.0.0.1:6379> sadd myset a b c
(integer) 3
127.0.0.1:6379> sadd myset2 c d e 
(integer) 3
127.0.0.1:6379> smembers myset
1) "c"
2) "a"
3) "b"
127.0.0.1:6379> smembers myset2
1) "c"
2) "e"
3) "d"
127.0.0.1:6379> sdiff myset myset2	#myset与myset2差集
1) "a"
2) "b"
127.0.0.1:6379> sdiff myset2 myset	#myset2与myset差集
1) "d"
2) "e"
127.0.0.1:6379> sinter myset myset2	#交集	共同好友可以这样实现
1) "c"
127.0.0.1:6379> sunion myset myset2	#并集
1) "c"
2) "e"
3) "a"
4) "b"
5) "d"

小结

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

共同关注、共同爱好、推荐好友

Hash(哈希)

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

bash
######################################################################################

127.0.0.1:6379> hset myhash name lpx	#set一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash lpx		#获取某个值
(nil)
127.0.0.1:6379> hget myhash name
"lpx"
127.0.0.1:6379> hmset myhash age 18 name liu	##set多个key-value
OK
127.0.0.1:6379> hmget myhash age name	#获取多个值
1) "18"
2) "liu"
127.0.0.1:6379> hgetall myhash	#获取全部值
1) "name"
2) "liu"
3) "age"
4) "18"

######################################################################################
127.0.0.1:6379> hgetall myhash
1) "name"
2) "liu"
3) "age"
4) "18"
5) "sex"
6) "man"
127.0.0.1:6379> hdel myhash sex	#删除指定hash表的指定key字段,对应的value值也就对应删除了
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "liu"
3) "age"
4) "18"

######################################################################################

127.0.0.1:6379> hgetall myhash
1) "name"
2) "liu"
3) "age"
4) "18"
127.0.0.1:6379> hlen myhash	#获取某个hash表的字段数
(integer) 2
127.0.0.1:6379> hexists myhash name	#判断某个hash表的某个字段是否存在
(integer) 1

######################################################################################

#只获得所有field
#只获得所有value

    127.0.0.1:6379> hkeys myhash	#只获得所有field
1) "name"
2) "age"
127.0.0.1:6379> hvals myhash	#只获得所有value
1) "liu"
2) "18"

######################################################################################

incr decr

127.0.0.1:6379> hset myhash num 1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "liu"
3) "age"
4) "18"
5) "num"
6) "1"
127.0.0.1:6379> hincrby myhash num 1	#自增1
(integer) 2
127.0.0.1:6379> hincrby myhash num -1	#自增-1
(integer) 1
127.0.0.1:6379> hsetnx myhash birthday 2021-02-06
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "liu"
3) "age"
4) "18"
5) "num"
6) "1"
7) "birthday"
8) "2021-02-06"
127.0.0.1:6379> hsetnx myhash birthday 2021-02-06	#不存在创建
(integer) 0
127.0.0.1:6379> hsetnx myhash birthday 2021-02-07	#已存返回0,不操作
0
(integer) 0
######################################################################################

小结

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

hash更适合对象的存储,string更加适合字符串的存储

Zset(有序集合)

bash
######################################################################################
127.0.0.1:6379> zadd myset 1 one 2 two	#添加多个值
(integer) 2
127.0.0.1:6379> zadd myset 3 three 4 four
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
######################################################################################

#排序
127.0.0.1:6379> zadd salary 2500 xiaohong	#添加四个元素
(integer) 1
127.0.0.1:6379> zadd salary 2500 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 5000 lisi
(integer) 1
127.0.0.1:6379> zadd salary 3500 wangwu
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf	#从低到高排序key做排序
1) "xiaohong"
2) "zhangsan"
3) "wangwu"
4) "lisi"
127.0.0.1:6379> zrangebyscore salary 0 +inf		#从低到高排序key做排序
1) "xiaohong"
2) "zhangsan"
3) "wangwu"
4) "lisi"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores	#从低到高排序,显示所有元素及值
1) "xiaohong"
2) "2500"
3) "zhangsan"
4) "2500"
5) "wangwu"
6) "3500"
7) "lisi"
8) "5000"
127.0.0.1:6379> zrangebyscore salary 3500 5000 withscores	#指定区间从低到高排序key做排序
1) "wangwu"
2) "3500"
3) "lisi"
4) "5000"
#从大到小排序
127.0.0.1:6379> zrevrange salary 0 -1
1) "lisi"
2) "wangwu"
3) "zhangsan"
4) "xiaohong"
127.0.0.1:6379> zrevrange salary 0 -1 withscores
1) "lisi"
2) "5000"
3) "wangwu"
4) "3500"
5) "zhangsan"
6) "2500"
7) "xiaohong"
8) "2500"
######################################################################################

#移除

127.0.0.1:6379> zrevrange salary 0 -1 withscores
1) "lisi"
2) "5000"
3) "wangwu"
4) "3500"
5) "zhangsan"
6) "2500"
7) "xiaohong"
8) "2500"
127.0.0.1:6379> zrem salary xiaohong	#移除指定元素
(integer) 1
127.0.0.1:6379> zrevrange salary 0 -1 withscores
1) "lisi"
2) "5000"
3) "wangwu"
4) "3500"
5) "zhangsan"
6) "2500"
######################################################################################

#统计区间中元素数量

127.0.0.1:6379> zrevrange salary 0 -1 withscores
1) "lisi"
2) "5000"
3) "wangwu"
4) "3500"
5) "zhangsan"
6) "2500"
127.0.0.1:6379> zcount salary 2500 4000
(integer) 2
127.0.0.1:6379> zcount salary 2500 5000
(integer) 3
127.0.0.1:6379> zcount salary 3000 5000
(integer) 2

三种特殊数据类型

geospatial地理位置

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

bash
######################################################################################
#geoadd
#两级是无法直接添加的,我们一般会下载城市数据,直接通过java程序一次性导入
#参数 key 值(纬度 经度 名称)
127.0.0.1:6379> geoadd china:city 115.07168 34.44539 suixian
(integer) 1
127.0.0.1:6379> geoadd china:city 115.65338 34.38804 suiyangqu

(integer) 1
127.0.0.1:6379> geoadd china:city 114.35708 36.09046 wenfengqu

(integer) 1
127.0.0.1:6379> geoadd china:city 113.81558 36.07804 linzhoushi 115.14621 34.64931 minquanxian
(integer) 2

######################################################################################

#获得当前定位:坐标值

127.0.0.1:6379> geopos china:city suixian	#获取指定的经度和纬度
1) 1) "115.07167786359786987"
   2) "34.44538914978334532"


######################################################################################

#geodist

127.0.0.1:6379> geodist china:city suixian suiyangqu	#查询睢县到睢阳区的距离默认m
"53754.2987"
127.0.0.1:6379> geodist china:city suixian suiyangqu km	#查询睢县到睢阳区的距离 km
"53.7543"

######################################################################################

#georadius

127.0.0.1:6379> georadius china:city 115.07168 34.44539 100 km	#查询100km(半径)以内的位置

1) "suixian"
2) "minquanxian"
3) "suiyangqu"

127.0.0.1:6379> georadius china:city 115.07168 34.44539 100 km withcoord withdist withhash count 2	#查询100km以内的位置,限定数量为2
1) 1) "suixian"
   2) "0.0002"						#距离 withdist
   3) (integer) 4064341297318991	#withhash
   4) 1) "115.07167786359786987"	#显示他人的定位信息 withcoord
      2) "34.44538914978334532"
2) 1) "minquanxian"
   2) "23.6867"	#距离
   3) (integer) 4065078118317270
   4) 1) "115.14621108770370483"
      2) "34.64931000177332265"


######################################################################################

#GEORADIUSBYMEMBER
#找出位于指定元素周围的其它元素
127.0.0.1:6379> GEORADIUSBYMEMBER china:city suixian 100 km	#
1) "suixian"
2) "minquanxian"
3) "suiyangqu"

######################################################################################

#geohash
#该命令返回11个字符串的geohash字符串
127.0.0.1:6379> geohash china:city suixian
1) "ww1gfw8dum0"	#将二维的字符串转换为一维的字符串,如果两个字符串越接近,距离就越近


######################################################################################

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

127.0.0.1:6379> zrange china:city 0 -1	#查看地图中全部元素
1) "suixian"
2) "suiyangqu"
3) "minquanxian"
4) "linzhoushi"
5) "wenfengqu"
127.0.0.1:6379> zrem china:city minquanxian	#移除地图中某一个元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "suixian"
2) "suiyangqu"
3) "linzhoushi"
4) "wenfengqu"


######################################################################################

hyperloglog

redis 在 2.8.9 版本添加了 HyperLogLog 结构。

Redis HyperLogLog 是用来做基数统计的算法

什么是基数?

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

一般用来网页的访问量uv(一个人访问网站多次,但还是算作一个人)

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

HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

测试使用

bash
######################################################################################

127.0.0.1:6379> pfadd mykey a b c d e f g h i j k l m n	#创建一组元素
(integer) 1
127.0.0.1:6379> pfcount mykey	#统计元素基数
(integer) 14
127.0.0.1:6379> pfadd mykey2 a q w e r t z x c v b	#创建一组元素
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 11
127.0.0.1:6379> pfmerge mykey3 mykey mykey2	#将两组元素并到第三组
OK
127.0.0.1:6379> pfcount mykey3
(integer) 20

######################################################################################

Bitmaps 位图

位存储

Bitmaps是一种特殊的“数据结构”,实质上是一个字符串,操作单元是位。二进制位来操作进行记录,就只有0和1两个状态可用

统计疫情感染人数:0 0 0 0 0 0 1 0 0 ...

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

测试

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

周一:1、周二:2、周三:3、周四:4、周五:5、周六:6、周日:0、

打卡状态:

​ -0:未打开

​ -1:已打卡

bash
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 0
(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 0
(integer) 0

查看某一天是否已经打卡

bash
127.0.0.1:6379> getbit sign 3
(integer) 0
127.0.0.1:6379> getbit sign 0
(integer) 1

统计打卡天数

bash
127.0.0.1:6379> bitcount sign	#统计这周打卡记录
(integer) 1

事务

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

一次性、顺序性、排他性,执行一系列的命令

bash
------队列 set set set...执行-----

redis事务没有隔离级别的概念

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

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

redis的事务:

​ -开启事务(multi)

​ -命令入队 (......)

​ -执行事务

锁:Redis可以实现乐观锁,watch

正常执行事务

bash
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

放弃事务

bash
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)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> discard	#取消事务,事务中的命令都不会执行
OK
127.0.0.1:6379> get k4
(nil)

编译时异常(代码有问题),事务中所有的命令都不会被执行

bash
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 k4 v4
QUEUED
127.0.0.1:6379(TX)> exec	#执行事务
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4		#所有的命令都不会执行
(nil)

运行时异常(1/0),如果事务队列中存在语法性,那么执行命令时,其他命令时可以正常执行的,错误命令抛异常

bash
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> get k1
"v1"
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)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range	#虽然这条命令报错了,但是依旧正常执行成功了
2) OK
3) "v2"