redis-数据类型
redis这各nosql没有表的概念,里面只有键值对,键没有什么好说的,就类型于变量的名字一样,而值就不一样了,常用的值类型有五种(笔试必背):
字符类型(string):啥都可以存
字典类型(hash):接近于mysql二维表结构
列表(list):[a,b,c,d,e],是后插入的数据在最顶端显示,比如微博、朋友圈的消息
集合(set):求交集、并集,应用有共同好友、共同关注等
有序集合(sorted set):做排行榜,热搜类的,自动排序。
通用操作
keys * 类型show tables,看看有多少个表名,查看所有的键的名字
[root@NFS ~]# redis-cli -a abc-123
127.0.0.1:6379> set a 3
OK
127.0.0.1:6379> set b 6
OK
127.0.0.1:6379> keys *
1) "b"
2) "a"
type:查看值的数据类型
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set b 9
OK
127.0.0.1:6379> type a
string #字符类型
127.0.0.1:6379> type b
string
DEL 删除一个(key)键,类似drop tables
[root@NFS ~]# redis-cli -a abc-123
127.0.0.1:6379> set a 3
OK
127.0.0.1:6379> set b 6
OK
127.0.0.1:6379> keys *
1) "b"
2) "a"
127.0.0.1:6379> del a
(integer) 1
127.0.0.1:6379> keys *
1) "b"
默认redis会一直通过内存进行各种操作,只要内存不满,就会一直占内存,只有内存满了之后才会有些释放操作,我们是可以进行人为干预的,比如我们可以定义键值之后,给一个时间,超过这个时间之后就自动释放了,不会占用内存了,就像下面这些例子。
EXPIRE(秒):
PEXPIRE(毫秒):
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> EXPIRE name 10 #设定10秒
(integer) 1
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> get name #10秒之后就没有了,比如验证码
(nil)
TTL与上面的对应,查看还剩于多少时间
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> EXPIRE name 30
(integer) 1
127.0.0.1:6379> TTL name
(integer) 26
127.0.0.1:6379> TTL name
(integer) 24
127.0.0.1:6379> set name zhangsan ex 60 #可在定义键值的时候一并把时间也给设置了
OK
persist:取消生存时间,水不过期
127.0.0.1:6379> set name zhangsan ex 60
OK
127.0.0.1:6379> PERSIST name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -1
127.0.0.1:6379> get name
"zhangsan"
字符类型
字符类型适合于做计数器,比如贴子、微博,积累多少个赞,关注人数、每多一个关注就加1,就是用字符类型来实现的。
//可同时设置多个键值
127.0.0.1:6379> mset xing zhang ming he age 22
OK
//同时获取多个值
127.0.0.1:6379> mget xing ming age
1) "zhang"
2) "he"
3) "22"
计数器:点击关注,每点击一次就会加1
127.0.0.1:6379> incr num
(integer) 1
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
//取消关注,每取消一次就会减去1
127.0.0.1:6379> decr num
(integer) 3
127.0.0.1:6379> decr num
(integer) 2
127.0.0.1:6379> decr num
(integer) 1
//显示当前粉丝的数量
127.0.0.1:6379> get num
"1" #显示粉丝数量
//暗箱操作,一个子就加个百万粉丝
127.0.0.1:6379> INCRBY num 1000000 暗箱操作,花钱就行了
(integer) 1000001
127.0.0.1:6379> get num
"1000001"
如果要用mysql实现这种计数就比较麻烦了,每个用户专门有一张表,每次点都得update一次,看的时候就得select一下,太麻烦,不如reid这种键值存储快速。
字典类型
用于存储变更类的,比如,用户信息,接近于mysql二维表结构
//每个键只能存一张表中的其中一行数据,stu指的是表名
127.0.0.1:6379> hmset stu id 101 name zhangsan age 22
OK
127.0.0.1:6379> keys *
1) "name"
2) "b"
3) "a"
4) "stu"
5) "age"
6) "xing"
7) "num"
8) "ming"
127.0.0.1:6379> HMGET stu id name age
1) "101"
2) "zhangsan"
3) "22"
myql中的数据要想存储到redis里面需要做一些处理,将其转换成redis的格式才可以。
列表类型
最新的消息会显示在列表的最前面,比如新浪微博,朋友圈。历史性的信息肯定要放到数据库里面,因为太占内存了,比如朋友圈里面仅展示三天的应用,比如天气预报,我们对去年的天气预报不感兴趣。
新浪的redis只存留5000个ID的最新消息,5000以外的都放到数据库当中了,第一个页面的加载不会通过数据库的,而是通过redis。
//边发6条朋友圈
127.0.0.1:6379> LPUSH wechat "today is nice day!"
(integer) 1
127.0.0.1:6379> LPUSH wechat "today is bad day!"
(integer) 2
127.0.0.1:6379> LPUSH wechat "today is good day!"
(integer) 3
127.0.0.1:6379> LPUSH wechat "today is verygood day!"
(integer) 4
127.0.0.1:6379> LPUSH wechat "today is DD day!"
(integer) 5
127.0.0.1:6379> LPUSH wechat "today is VV day!"
(integer) 6
//查看一下所有的朋友圈
127.0.0.1:6379> LRANGE wechat 0 -1 #看全部,从最新的开始显示
1) "today is VV day!"
2) "today is DD day!"
3) "today is verygood day!"
4) "today is good day!"
5) "today is bad day!"
6) "today is nice day!"
127.0.0.1:6379> LRANGE wechat 0 0 #看倒数第一天
1) "today is VV day!"
127.0.0.1:6379> LRANGE wechat 0 1 #看倒数两天
1) "today is VV day!"
2) "today is DD day!"
127.0.0.1:6379> LRANGE wechat 0 2 #看倒数三天
1) "today is VV day!"
2) "today is DD day!"
3) "today is verygood day!"
集合类型
应用于微博,共同关注,共同喜好,将一个用户所关注的人放到一个集合里面,将其所有的粉丝存在一个集合里面。
redis还提供了求交集(共同好友,并集、差集)等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能。
//定义一个集合,名为李小路
127.0.0.1:6379> SADD lxl jnl pgone ms mr lxlmami lxlbb baoqiang
(integer) 7
//定义另一个集合,名为贾奶凉
127.0.0.1:6379> sadd jnl lxl baoqiang huangbo xuzheng baodi
(integer) 5
//显示李小路的所有好友
127.0.0.1:6379> SMEMBERS lxl
1) "pgone"
2) "baoqiang"
3) "lxlmami"
4) "lxlbb"
5) "jnl"
6) "ms"
7) "mr"
//求交集
127.0.0.1:6379> sinter lxl jnl
1) "baoqiang"
//求并集
127.0.0.1:6379> SUNION lxl jnl
1) "lxlbb"
2) "ms"
3) "jnl"
4) "mr"
5) "baoqiang"
6) "lxl"
7) "huangbo"
8) "baodi"
9) "lxlmami"
10) "pgone"
11) "xuzheng"
//求差集
127.0.0.1:6379> SDIFF lxl jnl 差集,lxl有的,jnl没有的
1) "lxlmami"
2) "pgone"
3) "lxlbb"
4) "jnl"
5) "ms"
6) "mr"
127.0.0.1:6379> SDIFF jnl lxl jnl有的,lxl没有的
1) "huangbo"
2) "xuzheng"
3) "lxl"
4) "baodi"
//#将交集存起来,存到一个新的集合里面
127.0.0.1:6379> SINTER jnl lxl
1) "baoqiang"
127.0.0.1:6379> SINTERSTORE gongtong lxl jnl
(integer) 1
127.0.0.1:6379> SMEMBERS gongtong
1) "baoqiang"
有序集合
适用于排行榜,比如音乐排行榜单
//制定一个排行榜top,体面这首歌曲1000的播放量 thatgril是2000
127.0.0.1:6379> zadd top 1000 timian 2000 thatgirl 3000 lony
(integer) 3
//查看top进而所有的歌曲
127.0.0.1:6379> ZREVRANGE top 0 -1
1) "lony"
2) "thatgirl"
3) "timian"
//进一步显示
127.0.0.1:6379> ZREVRANGE top 0 -1 withscores #显示分数
1) "lony"
2) "3000"
3) "thatgirl"
4) "2000"
5) "timian"
6) "1000"
//暗箱操作,直接给timian加上一10000的播放量
127.0.0.1:6379> ZINCRBY top 10000 timain #加个10000分
"10000"
//体面这首歌冲到了排行榜的最前面
127.0.0.1:6379> ZREVRANGE top 0 -1
1) "timain"
2) "lony"
3) "thatgirl"
4) "timian"
#正常是每点一次,加一分
127.0.0.1:6379> ZINCRBY top 1 thatgirl
"2001"
127.0.0.1:6379> ZINCRBY top 1 thatgirl
"2002"
127.0.0.1:6379> ZINCRBY top 1 thatgirl
"2003"
127.0.0.1:6379> ZINCRBY top 1 thatgirl
"2004"
其它
消息队列
消息队列相当于集成商。生产者不直接对接生产者,不依赖于某一个生产者,不会因为一个生产者出一问题导致消费者无法购买的情况。
比如:
进入房间号,才能收到主播更新的通知。
加了别人好友,才能看到别人的朋友圈。
直播类、微博都用redis,缺点是这种消息模式只能看到订阅之后的消息,如下所示:
{{uploading-image-693089.png(uploading...)}}
左面相当于关注了baodi这个人,右面相当于baodi在开直播,baodi开直播时发了一个how are you,于是左边的关注者就收到了信息。
事务
multi
command1
command2
command3
command4
开启事务功能时,一组语句做为一个单元,首先是放到队列里面,并不执行,这一点和mysql的事务是类似的,比如取钱操作和账户减少这两个动作是一个事务,必须同时执行成功才能成功。
//当执行exec时,队列中的操作才会真正执行,要么全成功,要么全失败。
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a b
QUEUED
127.0.0.1:6379> set c d
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
如果是执行discard,会直接丢弃队列中所有的命令,而不做回滚。
乐观锁机制
redis有一个乐观锁机制挺好玩的,与mysql不同,mysql 一旦被锁定了某个表,这个表就会被加锁,别的用户是无法对这张表再次操作的,而redis则不同,比的是哪个用户先抢先执行,没有锁定的机制。
窗口1:
127.0.0.1:6379> set ticket 1 #发布一张票
OK
127.0.0.1:6379> watch ticket #观望一下
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379> set ticket 0 #添加到购物车,没付款
QUEUED
窗口2:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set ticket 0
QUEUED
127.0.0.1:6379> exec #抢先执行付款
1) OK
窗口1:付款的时候发现没票了!!!!
127.0.0.1:6379> exec
(nil)