1.Redis介绍
Redis是一种运行速度很快,并发很强,并且运行在内存上的NoSql ( not only sql )数据库
1.1 互联网需求的三高
- 高并发,高可扩,高性能
1.2 较传统数据库的优势
- NoSQL数据库无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。
- 而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦
1.3 Redis的常用使用场景
1.3.1 缓存
毫无疑问这是Redis当今最为人熟知的使用场景。在提升服务器性能方面非常有效;一些频繁被访问的数据,经常被访问的数据如果放在关系型数据库,每次查询的开销都会很大,而放在redis中,因为redis是放在内存中的可以很高效的访问。
1.3.2 排行榜
在使用传统的关系型数据库(mysql,oracle等)来做这个事儿,非常的麻烦,而利用Redis的SortSet(有序集合)数据结构能够简单的搞定;
1.3.3 计算器/限速器
利用Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;
限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力;
1.3.4 好友关系
利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能;
1.3.5 简单消息队列
除了Redis自身的发布/可订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦;
1.3.6 Session共享
以jsp为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。
2. Redis入门
2.1 Redis安装
2.1.1 上传tar.gz包,并解压
tar -zxvf redis-5.0.4.tar. gz
2.1.2 安装gcc
yum -y insta11 gcc
忘记是否安装过,可以使用gcc -v命令查看gcc版本,如果没有安装过,会提示命令不存在
2.1.3 进入redis目录,进行编译
make
2.1.4 编译之后,开始安装
make insta11
2.2 安装后的操作
2.2.1 后台运行方式
- redls默认不会使用后台运行,修改配置文件daemonize=yes。
vim /opt/redis-5.0.4/redis.conf
- 以配置文件的方式启动
cd /usr/local/bin
redis-server /opt/redis-5.0.4/redis.conf
- usr/local/bin 下的命令
- redis-server :启动 redis 服务
- redis-cli :进入 redis 命令客户端
- redis-benchmark : 性能测试的工具
- redis-check-aof : aof 文件进行检查的工具
- redis-check-dump : rdb 文件进行检查的工具
- redis-sentinel : 启动哨兵监控服务
2.2.2 关闭数据库
- 单实例关闭
redis-cli shutdown
- 多实例关闭
redis-cli -p 6379 shutdown
2.2.3 监听端口
netstat -lntp | grep 6379
- 检测后台进程是否存在
ps -ef | grep redis
2.2.4 性能测试
redis-benchmark
[root@VM-8-15-centos bin]# redis-benchmark
====== PING_INLINE ======
100000 requests completed in 1.32 seconds # 1.32秒处理了10万个请求
50 parallel clients
3 bytes payload
keep alive: 1
99.55% <= 1 milliseconds
99.82% <= 2 milliseconds
99.89% <= 3 milliseconds
99.90% <= 4 milliseconds
99.94% <= 5 milliseconds
99.95% <= 6 milliseconds
100.00% <= 6 milliseconds
75585.79 requests per second # 每秒处理的请求数量
====== PING_BULK ======
2.2.5 默认16个数据库
vim /usr/local/redis-5.0.13/redis.conf
databases 16
- 切换数据库
127.0.0.1:6379> select 16 # 切换16号数据库
(error) ERR DB index is out of range # 越界
127.0.0.1:6379> select 15
OK
2.2.6 查询当前数据库键的数量
dbsize
2.2.7 模糊查询key
(1) * :通配任意多个字符
- 查询所有的key
keys *
- 模糊查询n开头,后面随便多少个字符
keys n*
- 模糊查询e为最后一位,前面随便多少个字符
keys *e
- 双*模式,匹配任意多个字符:查询包含k的键
keys *k*
(2) ? :通配单个字符
- 模糊查询k字头,并且匹配一个字符
keys k?
- 你只记得第一个字母是k,他的长度是3
keys k??
(3) []:通配括号内的某一个字符
- 记得其他字母,就第二个字母可能是a或e
keys r[ae]dis
2.2.8 key的其它操作
- exists key :判断某个key是否存在
127.0.0.1:6379> exists k1
(integer) 1 #存在
127.0.0.1:6379> exists y1
(integer) 0 #不存在
- move key db :移动(剪切,粘贴)键到几号库
127.0.0.1:6379> move x1 8 #将x1移动到8号库
(integer) 1 #移动成功
127.0.0.1:6379>exists x1 #查看当前库中是否存在x1
(integer) 0 #不存在(因为已经移走了)
127.0.0.1:6379> select 8 #切换8号库
oK
127.0.0.1:6379[8]> keys * #查看当前库中的所有键
1) "x1"
- expire key 秒:为键设置过期时间
expire k1 60
-
ttl key:查看键还有多久过期( -1永不过期,-2已过期)
-
type key:查看键的数据类型
2.2.9 删除key
flushdb #删除当前数据库中的所有key
flushall #删除所有数据库中的key
3. 使用Redis
3.1 五大数据类型
3.1.1 字符串String
(1) set/get/del/append/strlen
127.0.0.1:6379> set k1 v1 #保存数据
OK
127.0.0.1:6379> set k2 v2 #保存数据
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> del k2 #删除数据k2
(integer) 1
127.0.0.1:6379> get k1 #获取数据k1
"v1"
127.0.0.1:6379> append k1 abc #往k1的值追加数据abc
(integer) 5
127.0.0.1:6379> get k1
"v1abc"
127.0.0.1:6379> strlen k1 #返回k1值的长度(字符数量)
(integer) 5
(2) incr/decr/incrby/decrby
加减操作,操作的必须是数字类型
127.0.0.1:6379> set k1 1 #初始化k1的值为1
OK
127.0.0.1:6379> incr k1 #k1自增1(相当于++)
(integer) 2
127.0.0.1:6379> incr k1
(integer) 3
127.0.0.1:6379> get k1
"3"
127.0.0.1:6379> decr k1 #k1自减1《相当于--)
(integer) 2
127.0.0.1:6379> decr k1
(integer) 1
127.0.0.1:6379> get k1
"1"
127.0.0.1:6379> incrby k1 3 #k1自增3〈相当于+=3)
(integer) 4
127.0.0.1:6379> get k1
"4"
127.0.0.1:6379> decrby k1 2 #相当于-=2
(integer) 2
127.0.0.1:6379> get k1
"2"
(3) getrange/setrange
类似 between...and...
127.0.0.1:6379> set k1 abcdef #初始化k1的值为abcdef
OK
127.0.0.1:6379> get k1
"abcdef"
127.0.0.1:6379> getrange k1 0 -1 # 查询k1全部值
"abcdef"
127.0.0.1:6379> getrange k1 0 3 # 查询k1下标0-3
"abcd"
127.0.0.1:6379> setrange k1 1 xxx # 从下标1开始替换
(integer) 6
127.0.0.1:6379> get k1
"axxxef"
(4) setex/setnx
- set with expir:添加数据的同时设置生命周期
127.0.0.1:6379> setex k1 10 v1 #添加k1 v1数据的同时,设置10秒的生命周期
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k1 # #已过期
(nil)
- set if not exist:添加数据的时候判断是否已经存在,防止已存在的数据被覆盖掉
127.0.0.1:6379> setnx k1 v1
(integer) 0 #添加失败,因为k1已经存在
127.0.0.1:6379> setnx k2 v2
(integer) 1 #添加成功
(5) mset/mget/msetnx
- m:more
127.0.0.1:6379> set k1 v1 k2 v2 # set不支持一次添加多条数据
(error) ERR syntax error
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> mget k1 k2 k3 #一次获取多条数据
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k3 v3 k4 v4 #一次添加多条数据时,如果添加的数据中有已经存在的,则失败
(integer) 0
127.0.0.1:6379> msetnx k4 v4 k5 v5 #一次添加多条数据时,如果添加的数据中都不存在的,则成功
(integer) 1
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k5"
4) "k2"
5) "k4"
(6) getset
- 先get后set
127.0.0.1:6379> getset k1 v1
(nil)
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> getset k1 v11
"v1"
127.0.0.1:6379> get k1
"v11"
3.1.2 列表List
(1)lpush/rpush/lrange
- 添加元素
127.0.0.1:6379> lpush list1 0 1 2 3 4 5 #从上往下添加
(integer) 6
127.0.0.1:6379> lrange list1 0 -1 #查询1ist01中的全部数据O表示开始,-1表示结尾
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> rpush list2 0 1 2 3 4 5 #从下往上添加
(integer) 6
127.0.0.1:6379> lrange list2 0 -1
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
(2) lpop/rpop
- 移除第一个元素
127.0.0.1:6379> lpop list2 #从左(上)边移除第一个元素
"0"
127.0.0.1:6379> rpop list2 #从右(下)边移除第一个元素
"5"
(3)lindex
- 根据下标查询元素(从左向右,自上而下)
127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "0"
127.0.0.1:6379> lindex list1 0
"5"
127.0.0.1:6379> lindex list1 5
"0"
(4)llen
- 返回集合长度
127.0.0.1:6379> llen list1
(integer) 6
(5)lrem
- 删除n个元素
127.0.0.1:6379> lrem list1 0 2
(integer) 1
127.0.0.1:6379> lrange list1 0 -1
1) "5"
2) "4"
3) "3"
4) "1"
5) "0"
(5)ltrim
- 截取指定范围的值,别的全扔掉
- ltrim key begindex endindex
127.0.0.1:6379> lrange list2 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> ltrim list2 0 3
OK
127.0.0.1:6379> lrange list2 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
(5)rpoplpush
- 从一个集合搞一个元素到另一个集合中(右出一个,左进一个)
127.0.0.1:6379> lrange list1 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list2 0 -1
1) "6"
2) "7"
3) "8"
4) "9"
127.0.0.1:6379> rpoplpush list1 list2
"5"
127.0.0.1:6379> lrange list1 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lrange list2 0 -1
1) "5"
2) "6"
3) "7"
4) "8"
5) "9"
(6)lset
- 改变某个下标的某个值
- lset key index value
127.0.0.1:6379> lrange list1 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lset list1 0 x
OK
127.0.0.1:6379> lrange list1 0 -1
1) "x"
2) "2"
3) "3"
4) "4"
(6)linsert
- 插入元素(指定某个元素之前/之后)
- linsert key before/after oldvalue newvalue
127.0.0.1:6379> lrange list1 0 -1
1) "x"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> linsert list1 after x java
(integer) 5
127.0.0.1:6379> lrange list1 0 -1
1) "x"
2) "java"
3) "2"
4) "3"
5) "4"
3.1.3 集合Set
- 和java中的set特点类似,不允许重复
(1)sadd/smembers/sismember
- 添加/查看/判断是否存在
127.0.0.1:6379> sadd set1 1 2 2 3 3 4 4 5 #添加元素(自动排除重复)
(integer) 5
127.0.0.1:6379> smembers set1 #查询set1集合
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> sismember set1 5
(integer) 1 # 存在
127.0.0.1:6379> sismember set1 6
(integer) 0 # 不存在
#注意:1和0可不是下标,而是布尔。
# 1 : true存在,2 : false不存在
(2)scard
- 获取集合中的元素个数
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> scard set1
(integer) 5
(3)srem
- 删除集合中的元素
- srem key value
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> srem set1 1
(integer) 1
127.0.0.1:6379> smembers set1
1) "2"
2) "3"
3) "4"
4) "5"
(4)srandmember
- 从集合中随机获取几个元素
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"
127.0.0.1:6379> srandmember set1 3
1) "3"
2) "7"
3) "1"
127.0.0.1:6379> srandmember set1 3
1) "4"
2) "7"
3) "1"
127.0.0.1:6379> srandmember set1 3
1) "7"
2) "1"
3) "5"
(5)spop
- 随机出栈(移除)
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"
127.0.0.1:6379> spop set1 #随机移除一个元素
"5"
127.0.0.1:6379> spop set1
"8"
127.0.0.1:6379> spop set1
"1"
127.0.0.1:6379> smembers set1
1) "2"
2) "3"
3) "4"
4) "6"
5) "7"
6) "9"
(5)数学集合类
- 交集:sinter
- 并集:sunion
- 差集: sdiff
127.0.0.1:6379> smembers set1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> smembers set2
1) "a"
2) "b"
3) "1"
4) "2"
5) "3"
127.0.0.1:6379> sinter set1 set2 # 交集 set1和set2共同存在的元素
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sunion set1 set2 # 并集 将set1和set2中所有元素合并起来(排除重复的)
1) "4"
2) "b"
3) "1"
4) "2"
5) "a"
6) "3"
7) "5"
127.0.0.1:6379> sdiff set1 set2 #在set1中存在,在set2中不存在
1) "4"
2) "5"
127.0.0.1:6379> sdiff set2 set1 #在set2中存在,在set1中不存在
1) "a"
2) "b"
3.1.4 哈希Hash
- 类似java里面的Map<String,Object> KV模式不变,但V是一个键值对
(1)hset/hget/hmset/hmget/ngetall/hdel
- 添加/得到/多添加/多得到/得到全部/删除属性
127.0.0.1:6379> hset user id 1001 #添加user,值为id=1001
(integer) 1
127.0.0.1:6379> hget user
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hget user id #查询user,必须指明具体的字段
"1001"
127.0.0.1:6379> hmset student id 101 name tom age 22 #添加学生student,属性—堆
OK
127.0.0.1:6379> hget student
(error) ERR wrong number of arguments for 'hget' command 必须指明具体的字段
127.0.0.1:6379> hget student name #获取学生名字
"tom"
127.0.0.1:6379> hget student name age #获取多属性 用hmget
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hmget student name age #获取学生姓名和年龄
1) "tom"
2) "22"
127.0.0.1:6379> hgetall student #获取学生全部信息
1) "id"
2) "101"
3) "name"
4) "tom"
5) "age"
6) "22"
127.0.0.1:6379> hdel student age #删除学生年龄属性
(integer) 1
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
(2)hlen
- 返回元素的属性个数
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
127.0.0.1:6379> hlen student
(integer) 2 # student属性的数量,id和name,共两个属性
(3)hexists
- 判断元素是否存在某个属性
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
127.0.0.1:6379> hexists student name
(integer) 1 # 存在
127.0.0.1:6379> hexists student age
(integer) 0 #不存在
(4)hkeys/hvals
- 获得属性的所有key/获得属性的所有value
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
127.0.0.1:6379> hkeys student
1) "id"
2) "name"
127.0.0.1:6379> hvals student
1) "101"
2) "tom"
(5)hincrby/hincrbyfloat
- 自增(整数)/自增(小数)
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
5) "age"
6) "18"
127.0.0.1:6379> hincrby student age 1
(integer) 19
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
5) "age"
6) "19"
(6)hsetnx
- 添加的时候,先判断是否存在
127.0.0.1:6379> hsetnx student age 20
(integer) 0
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
5) "age"
6) "18"
127.0.0.1:6379> hsetnx student sex 1
(integer) 1
127.0.0.1:6379> hgetall student
1) "id"
2) "101"
3) "name"
4) "tom"
5) "age"
6) "18"
7) "sex"
8) "1"
3.1.5 有序集合Zset
- 真实需求∶
- 充10元可享vip1;
- 充20元可享vip2;
- 充30元可享vip3;
- 以此类推...
(1)zadd/zrange ( withscores )
- 添加/查询
127.0.0.1:6379> zadd zset1 10 vip1 20 vip2 30 vip3 40 vip4 50 vip5
(integer) 5
127.0.0.1:6379> zrange zset1 0 -1 #查询数据
1) "vip1"
2) "vip2"
3) "vip3"
4) "vip4"
5) "vip5"
127.0.0.1:6379> zrange zset1 0 -1 withscores #带着分数查询数据
1) "vip1"
2) "10"
3) "vip2"
4) "20"
5) "vip3"
6) "30"
7) "vip4"
8) "40"
9) "vip5"
10) "50"
(2)zrangebyscore
- 模糊查询
- (:不包含
- limit :跳过几个截取几个
127.0.0.1:6379> zrangebyscore zset1 20 40 # 20 <= score <= 40
1) "vip2"
2) "vip3"
3) "vip4"
127.0.0.1:6379> zrangebyscore zset1 20 (40 # 20 <= score < 40
1) "vip2"
2) "vip3"
127.0.0.1:6379> zrangebyscore zset1 (20 (40 # 20 < score <40
1) "vip3"
127.0.0.1:6379> zrangebyscore zset1 10 40
1) "vip1"
2) "vip2"
3) "vip3"
4) "vip4"
127.0.0.1:6379> zrangebyscore zset1 10 40 limit 1 2 # 10 <= score <= 40,共返回四个,跳过第1个,取2个
1) "vip2"
2) "vip3"
(3)zrem
- 删除元素
127.0.0.1:6379> zr em zset01 vip5 #移除vip5
(integer) 1
(4)zcard/zcount/zrank/zscore
- 集合长度/范围内元素个数/得元素下标/通过值得分数
127.0.0.1:6379> zrange zset1 0 -1
1) "vip1"
2) "vip2"
3) "vip3"
4) "vip4"
5) "vip5"
127.0.0.1:6379> zcard zset1 #集合中元素的个数
(integer) 5
127.0.0.1:6379> zcount zset1 20 30 #分数在20~30之间,共有几个元素
(integer) 2
127.0.0.1:6379> zrank zset1 vip3 # vip3在集合中的下标(从上向下)
(integer) 2
127.0.0.1:6379> zscore zset1 vip2 #通过元素获得对应的分数
"20"
(5)zrevrange
- 逆序查询
127.0.0.1:6379> zrange zset1 0 -1 # 顺序查询
1) "vip1"
2) "vip2"
3) "vip3"
4) "vip4"
5) "vip5"
127.0.0.1:6379> zrevrange zset1 0 -1 # 逆序查询
1) "vip5"
2) "vip4"
3) "vip3"
4) "vip2"
5) "vip1"
(6)zrevrangebyscore
- 逆序范围查找
127.0.0.1:6379> zrevrangebyscore zset1 30 20 #逆序查询分数在30~20之间的(注意,先写大值,再写小值)
1) "vip3"
2) "vip2"
127.0.0.1:6379> zrevrangebyscore zset1 20 30 #如果小值在前则结果为nu11
(empty list or set)