Redis入门
1.Redis简介
1.1 背景
现象:12306春运期间网站崩溃、京东促销爆服务器…
问题现象:
- 海量用户
- 高并发
罪魁祸首–关系型数据库:
- 性能瓶颈:磁盘IO性能低下
- 扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
解决思路:
- 降低磁盘IO次数,越低越好 – 内存存储
- 去除数据间关系,越简单越好 – 不存储关系,仅存储数据
1.2 NoSQL概念
NoSQL:即Not-Only SQL(泛指非关系型的数据库),作为关系型数据库的补充。
作用:应对基于海量用户和海量数据前提下的数据处理问题
NoSQL,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题
特征:
- 可扩容,可伸缩
- 大数据量下高性能
- 灵活的数据类型
- 高可用
常见Nosql数据库:
- Redis
- memcache
- HBase
- MongoDB
解决方案(电商场景):
- 商品基本信息:MySQL
- 名称
- 价格
- 厂商
- 商品附加信息:MongoDB
- 描述
- 详情
- 评论
- 图片信息:分布式文件系统
- 搜索关键字:ES、Lucene、solr
- 热点信息:Redis、memcache、tair
- 高频
- 波段性
1.3 Redis概念
概念:Redis(REmote DIctionary Server)是用C语言开发的一个开源的高性能键值对(key-value)数据库
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助
特征:
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作
- 高性能。官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s
- 多数据类型支持
- 字符串类型 string
- 列表类型 list
- 散列类型 hash
- 集合类型 set
- 有序集合类型 zset/sorted_set
- 支持持久化,可以进行数据灾难恢复
2.Redis下载与安装
2.1 下载与安装
官网下载:https://redis.io/
中文官网:http://www.redis.cn/
windows下载:https://github.com/tporadowski/redis/releases
仓库:http://download.redis.io/releases/
Windows环境下解压即可
以下命令在CentOS命令行,或者SecureCRT连接中使用
下载安装包
- wget http://download.redis.io/releases/redis-5.0.0.tar.gz
解压安装包
- tar -xvf redis-5.0.0.tar.gz
编译(在解压地目录中执行)
- make
安装(在解压的目录中执行)
- make install
redis的部分命令:
- redis-server 服务器启动命令
- redis-cli 客户端启动命令
- redis.conf redis核心配置文件
- …
2.2 服务器与客户端启动
Redis服务器启动
启动服务器–参数启动
- redis-server [–port port]
范例
- redis-server --port 6379
启动服务器–配置文件启动
- redis-server config_file_name
范例
- redis-server redis.conf
Redis客户端启动
启动客户端
- redis-cli [-h host][-p port]
范例
- redis-cli -h 192.168.0.102 -p 6384
注意:服务器启动指定端口使用的是–port,客户端启动指定端口使用的是-p。-的数量不同
Redis基础环境设置约定
创建配置文件存储目录:
- mkdir conf
创建服务器文件存储目录(包含日志、数据、临时配置文件等)
- mkdir data
创建快速访问链接
- ln -s redis-5.0.0 redis
2.3 服务器配置
设置服务器以守护进程的方式运行,开启后服务器控制台中将打印服务器运行信息(同日志内容相同)
- daemonize yes|no
绑定主机地址
- bind IP
设置服务器端口号
- port port
设置服务器文件保存地址
- dir path
2.4 客户端配置
服务器允许客户端连接最大数量,默认0,表示无限制。当客户端连接到达上限后,Redis会拒接新的连接
- maxclients count
客户端闲置等待最大时长,达到最大值后关闭对应连接。如需关闭该功能,设置为0
- timeout seconds
2.5 日志配置
设置服务器以指定日志记录级别
- loglevel debug|verbose|notice|warining
日志记录文件名
- logfile filename
注意:日志级别开发期设置为verbose,生产环境中配置为notice,简化日志输出量,降低日志IO的频度
3.Redis基本操作
命令行模式工具使用思考
- 功能性命令
- 帮助信息查询
- 退出指令
- 清除屏幕信息
3.1 信息读写
设置key,value数据
- set key value
范例
- set name itheima
根据key查询对应的value,如果不存在,返回空(nil)
- get key
范例
- get name
3.2 帮助信息
获取命令帮助文档
- help [command]
范例
- help set
获取组中所有命令信息名称
- help [@group-name]
范例
- help @string
3.3 退出命令行客户端模式
退出客户端
- quit
- exit
快捷键
- ctrl+c
清除屏幕信息
- clear
4.数据类型
4.1 数据存储类型介绍
业务数据的特殊性
- 原始业务功能设计:
- 秒杀
- 618活动
- 双11活动
- 排队购票
- 运营平台监控到的突发高频访问数据
- 突发时政要闻,被强势关注微观
- 高频、复杂的统计数据
- 在线人数
- 投票排行榜
Redis数据类型(5种常用)
- string
- hash
- list
- set
- sorted set/zset(应用性较低)
redis数据存储格式
redis自身是一个Map,其中所有的数据都是采用key:value的形式存储
数据类型指的是存储的数据的类型,也就是value部分的类型,key部分永远都是字符串
4.2 string
存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型
存储数据的格式:一个存储空间保存一个数据
存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
string类型数据的基本操作:
添加/修改数据
- set key value
获取数据
- get key
删除数据
- del key
判定性添加数据
- setnx key value
添加/修改多个数据
- mset key1 value1 key2 value2 …
获取多个数据
- mget key1 key2 …
获取数据字符串个数(字符串长度)
- strlen key
追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
- append key value
[root@192 ~]# redis-cli
127.0.0.1:6379> set name itheima
OK
127.0.0.1:6379> set age 30
OK
127.0.0.1:6379> get name
"itheima"
127.0.0.1:6379> get age
"30"
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379> mget k1 k2 name
"v1"
"v2"
"itheima"
127.0.0.1:6379> strlen name
(integer) 7
127.0.0.1:6379> strlen age
(integer) 2
127.0.0.1:6379> del v2
(integer) 0
127.0.0.1:6379> get v2
(nil)
127.0.0.1:6379> setnx k4 v4
(integer) 1
127.0.0.1:6379> setnx k4 v5
(integer) 0
127.0.0.1:6379> append k4 v5
(integer) 4
127.0.0.1:6379> get k4
"v4v5"
127.0.0.1:6379>
string类型数据的扩展操作
设置数值数据加指定范围的值:
- incr key
- incrby key increment
- incrbyfloat key increment
设置数值数据减少指定范围的值:
- decr key
- decr key increment
设置数据具有指定的生命周期:
- setex key seconds value
- psetex key milliseconds value
127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
127.0.0.1:6379> get num
"3"
127.0.0.1:6379> incr num
(integer) 4
127.0.0.1:6379> get num
"4"
127.0.0.1:6379> incrby num 100
(integer) 104
127.0.0.1:6379> get num
"104"
127.0.0.1:6379> incr num2
(integer) 1
127.0.0.1:6379> incr name
(error) ERR value is not an integer or out of range
127.0.0.1:6379> setex t1 10 tt1
OK
127.0.0.1:6379> get t1
"tt1"
127.0.0.1:6379> get t1
"tt1"
127.0.0.1:6379> get t1
(nil)
127.0.0.1:6379> setex code 300 456213
OK
127.0.0.1:6379>
string类型数据操作的注意事项:
-
数据操作不成功的反馈与数据正常操作之间的差异
表示运行结果是否成功
- (integer) 0 --> false 失败
- (integer) 1 --> true 成功
表示运行结果
- (integer) 3 --> 3 3个
- (integer) 1 --> 1 1个
-
数据未获取到时,对应的数据为(nil),等同于null
-
数据最大存储量:512MB
-
string在redis内部存储默认就是一个字符串,当遇到增减类操作incr、decr时会转成数值型进行计算
-
按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis数据上限范围,将报错
9223372036854775807(java种Long型数据最大值,Long.MAX_VALUE)
-
redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的影响
应用场景
主页高频访问信息显示控制,例如新浪微博大V主页面显示粉丝数与微博数量
解决方案
-
在redis中为大V用户设定用户信息,以户主键和属性值作为key,后台设定定时刷新策略即可
eg: user🆔3506728370:fans --> 12210947
eg: user:id :3506728370:blogs --> 6164
eg: user:id :3506728370:focuses --> 83
-
也可以使用json格式保存数据
eg: user:id :3506728370 --> {“fans”:12210947,“blogs”:6164,“focuses”:83}
127.0.0.1:6379> set user:id:123456:fans 9874562
OK
127.0.0.1:6379>
key的设置约定
数据库中热点数据key命名惯例
4.3 hash
数据存储的困惑
对象类数据的存储如果具有较频繁的更新需求操作会显得笨重
hash类型
新的存储需求:对一系列存储的数据进行编组,管理方便,典型应用存储对象信息
而需要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用hash表结构实现数据存储
hash存储结构优化:
- 如果field数量较少,存储结构优化为类数组结构
- 如果field数量较多,存储结构使用HashMap结构
hash类型数据的基本操作
添加/修改数据
- hset key field value
获取数据
- hget key field
- hgetall key
删除数据
- hdel key field1 [field2]
设置field的值,如果该field存在则不做任何操作
- hsetnx key field value
添加/修改多个数据
- hmset key field1 value1 field2 value2 …
获取多个数据
- hmget key field1 field2 …
获取哈希表中字段的数量
- hlen key
获取哈希表中是否存在指定的字段
- hexists key field
127.0.0.1:6379> hset user:123 name itcast
(integer) 1
127.0.0.1:6379> hset user:123 age 12
(integer) 1
127.0.0.1:6379> hget user:123 name
"itcast"
127.0.0.1:6379> hgetall user:123
"name"
"itcast"
"age"
"12"
127.0.0.1:6379> hdel user:123 age
(integer) 1
127.0.0.1:6379> hgetall user:123
"name"
"itcast"
127.0.0.1:6379> hlen user:123
(integer) 1
127.0.0.1:6379> hmset user:123 a a1 b b1 c c1
OK
127.0.0.1:6379> hlen user:123
(integer) 5
127.0.0.1:6379> hgetall user:123
"name"
"itcast"
"a"
"a1"
"b"
"b1"
"c"
"c1"
"age"
"12"
127.0.0.1:6379>
hash类数据扩展操作
获取哈希表中所有的字段名或字段值
- hkeys key
- hvals key
设置指定字段的数值数据增加指定范围的值
- hincrby key field increment
- hincrbyfloat key field increment
127.0.0.1:6379> hmset h1 a 123 b 345
OK
127.0.0.1:6379> hincrby h1 a 100
(integer) 223
127.0.0.1:6379> hincrby h1 a -1000
(integer) -777
127.0.0.1:6379> hkeys h1
"a"
"b"
127.0.0.1:6379> hvals h1
"-777"
"345"
127.0.0.1:6379>
hash类型数据操作的注意事项:
- hash类型中value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
- 每个hash可以存储2^32-1个键值对
- hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
- hgetall操作可以获取全部属性,如果内部field过多,遍历整个数据效率就会很低,有可能称为数据访问瓶颈
应用场景
双11活动日,销售手机充值卡的商家对移动、联通、电信的30元、50元、100元商品推出抢购活动,每种商品抢购上限1000张
解决方案:
- 以商家id作为key
- 将参与抢购的商品id作为field
- 将参与抢购的商品数量作为对应的value
- 抢购时使用降值的方式控制商品数量
127.0.0.1:6379> hmset id:001 c30 1000 c50 1000 c100 1000
OK
127.0.0.1:6379> hincrby id:001 c50 -2
(integer) 998
127.0.0.1:6379> hincrby id:001 c30 -5
(integer) 995
127.0.0.1:6379> hincrby id:001 c100 -1
(integer) 999
127.0.0.1:6379> hincrby id:001 c100 -1
(integer) 998
127.0.0.1:6379> hincrby id:001 c100 -1
(integer) 997
127.0.0.1:6379> hincrby id:001 c100 -10
(integer) 987
127.0.0.1:6379> hgetall id:001
"c30"
"995"
"c50"
"998"
"c100"
"987"
注意:实际情况下还有超卖等问题
4.4 list
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现
list类型数据基本操作
添加/修改数据
- lpush key value1 [value2] …
- rpush key value1 [value2] …
获取数据
- lrange key start stop
- lindex key index
- llen key
获取并移除数据
- lpop key
- rpop key
127.0.0.1:6379> lpush list1 zhangsan lisi wangwu zhaoliu
(integer) 4
127.0.0.1:6379> lrange list1 0 3
1) "zhaoliu"
2) "wangwu"
3) "lisi"
4) "zhangsan"
127.0.0.1:6379> lrange list1 0 -1
1) "zhaoliu"
2) "wangwu"
3) "lisi"
4) "zhangsan"
127.0.0.1:6379> lpush list1 hehe
(integer) 5
127.0.0.1:6379> lrange list1 0 -1
1) "hehe"
2) "zhaoliu"
3) "wangwu"
4) "lisi"
5) "zhangsan"
127.0.0.1:6379> rpush list1 haha
(integer) 6
127.0.0.1:6379> lrange list1 0 -1
1) "hehe"
2) "zhaoliu"
3) "wangwu"
4) "lisi"
5) "zhangsan"
6) "haha"
127.0.0.1:6379> lpop list1
"hehe"
127.0.0.1:6379> lrange list1 0 -1
1) "zhaoliu"
2) "wangwu"
3) "lisi"
4) "zhangsan"
5) "haha"
127.0.0.1:6379> llen list1
(integer) 5
127.0.0.1:6379> rpop list1
"haha"
127.0.0.1:6379> llen list1
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "zhaoliu"
2) "wangwu"
3) "lisi"
4) "zhangsan"
127.0.0.1:6379> lindex list1 0
"zhangsan"
127.0.0.1:6379> lindex list1 4
(nil)
list类型数据扩展操作
移除指定数据
- lrem key count value
规定时间内获取并移除数据
- blpop key1 [key2] timeout
- brpop key1 [key2] timeout
- brpoplpush source destination timeout
127.0.0.1:6379> lpush list2 a b c d e f g
(integer) 7
127.0.0.1:6379> lrange list2 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "c"
6) "b"
7) "a"
127.0.0.1:6379> lrem list2 1 c
(integer) 1
127.0.0.1:6379> lrange list2 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "b"
6) "a"
127.0.0.1:6379> rpush list2 d e d e d e h e
(integer) 14
127.0.0.1:6379> lrange list2 0 -1
1) "g"
2) "f"
3) "e"
4) "d"
5) "b"
6) "a"
7) "d"
8) "e"
9) "d"
10) "e"
11) "d"
12) "e"
13) "h"
14) "e"
127.0.0.1:6379> lrem list2 3 d
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "g"
2) "f"
3) "e"
4) "b"
5) "a"
6) "e"
7) "e"
8) "d"
9) "e"
10) "h"
11) "e"
127.0.0.1:6379> lrem list2 3 d
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> lpush a a1
(integer) 1
127.0.0.1:6379> lpush b b1
(integer) 1
127.0.0.1:6379> lpush c c1
(integer) 1
127.0.0.1:6379> blpop a 5
1) "a"
2) "a1"
127.0.0.1:6379> blpop a 5
(nil)
(5.00s)
127.0.0.1:6379> blpop a 5
(nil)
(5.03s)
127.0.0.1:6379> blpop b c 5
1) "b"
2) "b1"
127.0.0.1:6379> blpop b c 5
1) "c"
2) "c1"
127.0.0.1:6379> blpop b c 5
(nil)
(5.03s)
list类型数据操作注意事项:
- list中保存的数据都是string类型的,数据总容量是有限的,最多2^32-1个元素(4291967295)
- list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
- 获取全部数据操作结束索引设置为-1
- list可以对数据进行分页操作,通常第一页的信息来自于list,第二页及更多的信息通过数据库的形式加载
应用场景
企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出?
解决方案
- 依赖list的数据具有顺序的特征对信息进行管理
- 使用队列模型解决多路信息汇总合并的问题
- 使用栈模型解决最新消息的问题
127.0.0.1:6379> rpush logs a:out
(integer) 1
127.0.0.1:6379> rpush logs a]b:out
(integer) 2
127.0.0.1:6379> rpush logs a:print
(integer) 3
127.0.0.1:6379> rpush logs c:in
(integer) 4
127.0.0.1:6379> lrange logs 0 -1
1) "a:out"
2) "b:out"
3) "a:print"
4) "c:in"
127.0.0.1:6379>
4.5 set
set类型
新的存储需求:存储大量的数据,在查询方面提供更高的效率
需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
set类型数据基本操作
添加数据
- sadd key member1 [member2]
获取全部数据
- smembers key
删除数据
- srem key member1 [member2]
获取集合数据总量
- scard key
判断集合中是否包含指定数据
- sismember key member
随机获取集合中指定数量的数据
- srandmember key [count]
随机获取集合中的某个数据并将该数据移除集合
- spop key [count]
127.0.0.1:6379> sadd set1 a
(integer) 1
127.0.0.1:6379> sadd set1 b
(integer) 1
127.0.0.1:6379> sadd set1 c
(integer) 1
127.0.0.1:6379> sadd set1 a
(integer) 0
127.0.0.1:6379> sadd set1 c
(integer) 0
127.0.0.1:6379> smembers set1
1) "c"
2) "a"
3) "b"
127.0.0.1:6379> srem set1 c
(integer) 1
127.0.0.1:6379> smembers set1
1) "a"
2) "b"
127.0.0.1:6379> srem set1 c
(integer) 0
127.0.0.1:6379> scard set1
(integer) 2
127.0.0.1:6379> sismember set1 c
(integer) 0
127.0.0.1:6379> sismember set1 a
(integer) 1
set类型数据的扩展操作
求两个集合的交、并、差集
- sinter key1 [key2 …]
- sunion key1 [key2 …]
- sdiff key1 [key2 …]
求两个集合的交、并、差集并存储到指定集合中
- sinterstore destination key1 [key2 …]
- sunionstore destination key1 [key2 …]
- sdiffstore destination key1 [key2 …]
将指定数据从原始集合中移动到目标集合中
- smove source destination member
127.0.0.1:6379> sadd s1 100 666 itheima
(integer) 3
127.0.0.1:6379> sadd s2 100 itheima
(integer) 2
127.0.0.1:6379> sadd s3 666
(integer) 1
127.0.0.1:6379> sadd s4 itcast
(integer) 1
127.0.0.1:6379> sinter s1 s3
1) "666"
127.0.0.1:6379> sinter s1 s2
1) "100"
2) "itheima"
127.0.0.1:6379> sinter s1 s2 s3
(empty list or set)
127.0.0.1:6379> sunion s1 s4
1) "itcast"
2) "100"
3) "666"
4) "itheima"
127.0.0.1:6379> sdiff s1 s2
1) "666"
127.0.0.1:6379> sdiff s2 s1
(empty list or set)
127.0.0.1:6379> hset s1 100 100
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379>
set类型数据操作的注意事项:
- set类型不允许数据重复,如果添加的数据在set中已经存在,将只保留一份
- set虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
应用场景
黑名单:
资讯类信息类网站追求高访问量,但是由于其信息的价值,往往容易被不法分子利用,通过爬虫技术,快速获取信息,个别特种行业网站信息通过爬虫获取分析后,可以转换成商业机密进行出售。例如第三方火车票、机票、酒店刷票代购软件,电商刷评论、刷好评
同时爬虫带来的伪流量也会给经营者带来错觉,产生错误的决策,有效避免网站被爬虫反复爬取成为每个网站都要考虑的基本问题。在基于技术层面区分出爬虫用户后,需要将此类用户进行有效的屏蔽,这就是黑名单的典型应用。
ps:不是说爬虫一定做摧毁性的工作,有些小型网站需要爬虫为其带来一些流量。
白名单:
对于安全性更高的应用访问,仅仅靠黑名单是不能解决安全问题的,此时需要设定可访问的用户群体,依赖白名单做更为苛刻的访问验证
解决方案:
- 基于经营战略设定问题用户发现、鉴别规则
- 周期性更新满足规则的用户黑名单,如加入set集合
- 用户行为信息达到后与黑名单进行比对,确认行为去向
- 黑名单过滤IP地址:应用于开放游客访问权限的信息源
- 黑名单过滤设备信息:应用于限定访问设备的信息源
- 黑名单过滤用户:应用于基于访问权限的信息源
4.6 数据类型实践案例
业务场景
使用微信的过程中,当微信接收消息后,会默认将最近接收的消息置顶,当多个好友及关注的订阅号同时发送消息时,该排序会不停的进行交替。同时还可以将重要的会话设置为置顶。一旦用户离线后,再次打开微信时,消息该按照什么样的顺序显示?
解决方案:
- 依赖list的数据具有顺序的特征对消息进行管理,将list结构作为栈使用
- 对置顶与普通会话分别创建独立的list分别管理
- 当某个list中接收到用户消息后,将消息发送方的id从list的一侧加入list(此处设定左侧)
- 多个相同id发出的消息反复入栈会出现问题,在入栈之前无论是否具有当前id对应的消息,先删除对应id
- 推送消息时先推送置顶会话list,再推送普通会话list,推送完成的list清除所有数据
- 消息的数量,也就是微信用户对话数量采用计数器的思想另行记录,伴随list操作同步更新
127.0.0.1:6379> lrem 100 1 200
(integer) 0
127.0.0.1:6379> lpush 100 200
(integer) 1
127.0.0.1:6379> lrem 100 1 300
(integer) 0
127.0.0.1:6379> lpush 100 300
(integer) 2
127.0.0.1:6379> lrem 100 1 400
(integer) 0
127.0.0.1:6379> lpush 100 400
(integer) 3
127.0.0.1:6379> lrem 100 1 300
(integer) 1
127.0.0.1:6379> lpush 100 300
(integer) 3
127.0.0.1:6379> lrem 100 1 200
(integer) 1
127.0.0.1:6379> lpush 100 200
(integer) 3
127.0.0.1:6379> lrange 100 0 -1
1) "200"
2) "300"
3) "400"
127.0.0.1:6379> hincrby u:100 u:200 1
(integer) 1
127.0.0.1:6379> hincrby u:100 u:300 1
(integer) 1
127.0.0.1:6379> hincrby u:100 u:400 1
(integer) 1
127.0.0.1:6379> hincrby u:100 u:300 1
(integer) 2
127.0.0.1:6379> hincrby u:100 u:200 1
(integer) 2
127.0.0.1:6379> hgetall u:100
1) "u:200"
2) "2"
3) "u:300"
4) "2"
5) "u:400"
6) "1"
127.0.0.1:6379>
5.常用指令
5.1 key常用指令
key应该设计哪些操作?
- key是一个字符串,通过key获取redis中保存的数据
- 对于key自身状态的相关操作,例如:删除,判断存在,获取类型等
- 对于key有效性控制相关操作,例如:有效期设定,判定是否有效,有效状态的切换等
- 对于key快速查询操作,例如:按指定策略查询key
- …
key基本操作
删除指定key
- del key
获取key是否存在
- exists key
获取key的类型
- type key
127.0.0.1:6379> set name itheima
OK
127.0.0.1:6379> type name
string
127.0.0.1:6379> lpush list1 aa
(integer) 5
127.0.0.1:6379> type list1
list
127.0.0.1:6379>
key扩展操作
排序
- sort
改名
- rename key newkey
- renamenx key newkey
127.0.0.1:6379> rename list1 list2
OK
127.0.0.1:6379> lrange list1 0 -1
(empty list or set)
127.0.0.1:6379> lrange list2 0 -1
1) "aa"
2) "zhaoliu"
3) "wangwu"
4) "lisi"
5) "zhangsan"
127.0.0.1:6379>
127.0.0.1:6379> lpush list1 cc
(integer) 1
127.0.0.1:6379> lpush list1 bb
(integer) 2
127.0.0.1:6379> lpush list1 aa
(integer) 3
127.0.0.1:6379> lpush list1 dd
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "dd"
2) "aa"
3) "bb"
4) "cc"
127.0.0.1:6379> sort list1
(error) ERR One or more scores can't be converted into double
127.0.0.1:6379> sort list1 alpha
1) "aa"
2) "bb"
3) "cc"
4) "dd"
127.0.0.1:6379> lrange list1 0 -1
1) "dd"
2) "aa"
3) "bb"
4) "cc"
127.0.0.1:6379> sort list1 alpha desc
1) "dd"
2) "cc"
3) "bb"
4) "aa"
key扩展操作(时效性控制)
为指定key设置有效期
- expire key seconds
- pexpire key milliseconds
- expireat key timestamp
- pexpireat key milliseconds-timestamp
获取key的有效时间
-
ttl key
-
pttl key
切换你key从时效性转换为永久性
- persist key
127.0.0.1:6379> set aa 123
OK
127.0.0.1:6379> ttl aa
(integer) -1
127.0.0.1:6379> ttl bb
(integer) -2
127.0.0.1:6379> setex cc 30 123
OK
127.0.0.1:6379> ttl cc
(integer) 25
127.0.0.1:6379> ttl cc
(integer) 20
127.0.0.1:6379> ttl cc
(integer) 17
127.0.0.1:6379> ttl cc
(integer) 13
127.0.0.1:6379> pttl cc
(integer) 4503
127.0.0.1:6379> ttl cc
(integer) -2
127.0.0.1:6379> setex dd 30 123
OK
127.0.0.1:6379> ttl dd
(integer) 25
127.0.0.1:6379> pttl dd
(integer) 20536
127.0.0.1:6379> ttl dd
(integer) 17
127.0.0.1:6379> persist dd
(integer) 1
127.0.0.1:6379> ttl dd
(integer) -1
127.0.0.1:6379>
key扩展操作(查询模式)
查询key
- keys pattern
查询模式规则
* 匹配任意数量的任意符号 ? 配合一个任意符号 [] 匹配一个指定符号
keys * 查询所有
keys it* 查询所有以it开头
keys *heima 查询所有以heima结尾
keys ??heima 查询所有前面两个字符任意,后面以heima结尾
keys user:? 查询所有以user:开头,最后一个字符任意
keys u[st]er:l 查询所有以u开头,以er:l结尾,中间包含一个字母,s或t
127.0.0.1:6379> keys *
1) "dd"
2) "aa"
127.0.0.1:6379> keys a?
1) "aa"
127.0.0.1:6379> set ac 123
OK
127.0.0.1:6379> set ad 123
OK
127.0.0.1:6379> set bd 123
OK
127.0.0.1:6379> keys a?
1) "ac"
2) "aa"
3) "ad"
127.0.0.1:6379> keys ?d
1) "ad"
2) "bd"
127.0.0.1:6379> keys a[ad]
1) "aa"
2) "ad"
127.0.0.1:6379> keys a[ae]
1) "aa"
127.0.0.1:6379> keys a[ae]*
1) "aa"
5.2 数据库常用指令
数据库
key的重复问题
- key是由程序员定义的
- redis在使用过程中,伴随着操作数据量的增加,会出现大量的数据以及对应的key
- 数据不区分种类、类别混杂在一起,极易出现重复或冲突
解决方案
- redis为每个服务提供有16个数据库,编号从0到15
- 每个数据库之间的数据相互独立
db基本操作
切换数据库
- select index
其他操作
- ping
127.0.0.1:6379> set name 123
OK
127.0.0.1:6379> get name
"123"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
(nil)
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> get name
"123"
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> select 16
(error) ERR DB index is out of range
127.0.0.1:6379[15]> select 0
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
db扩展操作
数据移动
- move key db
数据总量
- dbsize
数据清除
- flushdb
- flushall
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> set name itheima
OK
127.0.0.1:6379> get name
"itheima"
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
"itheima"
127.0.0.1:6379[1]> dbsize
(integer) 1
127.0.0.1:6379[1]> set age 39
OK
127.0.0.1:6379[1]> dbsize
(integer) 2
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> set name itheima
OK
127.0.0.1:6379> get name
"itheima"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
"itheima"
127.0.0.1:6379[1]> select 0
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
(nil)
下文:Redis基础