这次我们来说说我们的redis,在我们的redis的认知里,最熟悉的就是用redis作为缓存使用,还有我们的分布式session,其实还有很多redis的使用,还有redis的哨兵模式等等。
Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。(百度百科)
安装(linux为例讲解):
1.先安装一下C语言的包,redis的底层是用C来写的,如果不安装可能安装的时候会报错的。输入$ yum install gcc
2.获得redis资源,输入 $ wget http://download.redis.io/releases/redis-5.0.5.tar.gz
3.开始安装,输入以下命令即可
$ tar -zxvf redis-5.0.5.tar.gz;
$ cd redis-5.0.5;
$ make
4.修改配置,直接输入vim redis.conf,然后跳转到136行(差不多就是136行,版本不同文件可能存在差异),daemonize no设置为daemonize yes,
5.启动,输入./src/redis-server redis.conf 即可启动了,输入ps -ef|grep redis可以看到redis是否启动成功。
6.输入./src/redis-cli 即可进入客户端,quit退出。
官网有如何安装的教程这里就不在继续赘述了。
redis的数据结构:
我们都知道redis是键值对的形式来存储数据的,其实内部还有几种结构的,也是我们常见常用的结构,这里来详细说一下。
我们接下来会围绕这五种数据结构来展开去讲。
结构与常见命令场景
String常见操作
SET KEY VALUE //存入单个字符串键值对,最常见不过了,单值缓存,就不说啦。
MSET KEY VALUE//批量写入字符串,一般来存对象。看下实例
这里有一张职员表,内容如下
只存了姓名和年龄两个字段,以前我们的方式都是设置一个key,然后把姓名和年龄转为json然后再存储对吧。
我们来看一下我们的MSet命令是如何使用并存储的。
mset user:1:name zhang user:1:age 1也就是说我们一口气直接把user表内id为1的对象都存在了redis里,然后我们用mget user:1:name user:1:age。就可以一次性取出来了。
SETNX //存入一个不存在的字符串键值对,我们来看一下实例。最简单的分布式锁就看可以用他来实现。
127.0.0.1:6379> setnx lock:user true (integer) 1 127.0.0.1:6379> setnx lock:user true (integer) 0就是说只允许一次的写入,写入成功才会返回1,否则是0,我们的线程争抢就看谁优先写入啦。
GET KEY//取得一个键对应的字符串,上文提到过 ,不再赘述
MGET KEY//批量获得键对应的字符串,上文提到过 ,不再赘述
EXPIRE KEY SECONDS //设置一个键的过期时间,单位是秒
127.0.0.1:6379> expire lock:user 1 (integer) 1 127.0.0.1:6379> get lock:user (nil)原子加减
INCR key //将key中存储的数字值加1,一般用在新闻点赞计数操作 incr {文章:id}
127.0.0.1:6379> incr article:xiaocai (integer) 1 127.0.0.1:6379> incr article:xiaocai (integer) 2 127.0.0.1:6379> incr article:xiaocai (integer) 3 127.0.0.1:6379> incr article:xiaocai (integer) 4
DECR key //将key中存储的数字值减1,一般用在新闻点赞计数操作
INCRBY KEY increment //将key所存储的值加上increment
DECRBY key decrement //将key所存储的值减去decrement
哈希Hash常见操作
hash结构和我们的String有些不同,原本String是一个key对应一个value,而我们的hash是一个redis_key,对应一组值,内部还有hash_key对应我们的hash_value。但是用法几乎是一致
hset key hash_key hash_value //存储一个hash表的key的键值对
127.0.0.1:6379> hset user 1:name zhao (integer) 0 127.0.0.1:6379> hget user 1:name "zhao"hsetnx key hash_key hash_value //存储一个不存在的hash表的key的键值对
127.0.0.1:6379> hsetnx lock user:locak true (integer) 1 127.0.0.1:6379> hsetnx lock user:locak true (integer) 0hmset key hash_key hash_value //存储一个hash表的多个key的键值对
127.0.0.1:6379> hmset user 1:name zhoao 1:age 11 OK 127.0.0.1:6379> hmget user 1:name 1:age 1) "zhoao" 2) "11"hget key hash_key //获取哈希表key对应的多个hash键值
hdel key hash_key //删除哈希表key中的hash键值对
hlen key //返回所有哈希表key中该键的数量
127.0.0.1:6379> hlen user (integer) 2hgetall key //返回所有哈希表key中所有键的键值对
127.0.0.1:6379> hgetall user 1) "1:name" 2) "zhoao" 3) "1:age" 4) "11"hash哈希的有点在于,对于同类的数据更好的整合在了一起,方便数据的管理,相比String操作消耗的内存与cpu更小(以后会详细说明为什么小),空间占用也是比String要小的,但在集群的架构下不适合大规模的使用。
列表常见操作
lpush key value //将一个或者多个值value插入到key列表的最左边left
127.0.0.1:6379> lpush liredis a (integer) 1 127.0.0.1:6379> lpush liredis b (integer) 2 127.0.0.1:6379> lpush liredis c (integer) 3rpush key value //将一个或者多个值value插入到key列表的最右边right
127.0.0.1:6379> rpush liredis 1 (integer) 4 127.0.0.1:6379> rpush liredis 2 (integer) 5 127.0.0.1:6379> rpush liredis 3 (integer) 6lpop key //移除并返回对应key的头元素(最左边的元素)
127.0.0.1:6379> lpop liredis "c"rpop key //移除并返回对应key的尾元素(最右边的元素)
127.0.0.1:6379> rpop liredis "3"lrange key start stop //返回列表key中start到stop的区间元素,需要注意的是角标是从0开始的,start和stop都包含在内的,不如我们输入 lrange redis_key 0 2 ,则表示取得第0,1,2三个元素。
127.0.0.1:6379> lrange liredis 1 2 1) "a" 2) "1"blpop key timeout //从列表key的表头(最左侧)弹出第一个元素,若队列中没有元素,阻塞等待timeout秒,如果timeout=0,一直等待
127.0.0.1:6379> blpop liredis 1 1) "liredis" 2) "b" 127.0.0.1:6379> blpop liredis 1 1) "liredis" 2) "a" 127.0.0.1:6379> blpop liredis 1 1) "liredis" 2) "1" 127.0.0.1:6379> blpop liredis 1 1) "liredis" 2) "2" 127.0.0.1:6379> blpop liredis 1 (nil) (1.04s)brpop key timeout //从列表key的表尾(最右侧)弹出末尾元素,若队列中没有元素,阻塞等待timeout秒,如果timeout=0,一直等待
更好的理解我们的列表命令,我们可以从数据结构的角度来说一下。
栈:先进先出,也就是我们的Lpush+lpop,或者rpush+rpop就可以实现的。
队列:先进后出,也就是我们的Lpush+rpop,或者rpush+lpop就可以实现的。
阻塞队列:lpush+brpop也就可以实现啦。
set集合常见操作
sadd key member //往集合key中存入元素,元素存在则忽略
127.0.0.1:6379> sadd setredis 1 2 3 4 5 (integer) 5 127.0.0.1:6379> sadd setredis 1 2 (integer) 0srem key member //从集合key中删除元素
127.0.0.1:6379> srem setredis a (integer) 0 127.0.0.1:6379> srem setredis 1 (integer) 1smembers key //获取集合中的所有元素
127.0.0.1:6379> smembers setredis 1) "2" 2) "3" 3) "4" 4) "5"scard key //获取集合key中的元素个数
127.0.0.1:6379> scard setredis (integer) 4sismember key member //判断member元素是否存在于集合key中
127.0.0.1:6379> sismember setredis a (integer) 0 127.0.0.1:6379> sismember setredis 2 (integer) 1srandmember key count //从集合key中选出count个元素,元素不从key中删除
127.0.0.1:6379> srandmember setredis 2 1) "5" 2) "4"spop key count //从集合key中选出count个元素,元素从key中删除,抽奖小程序可以使用这个。
127.0.0.1:6379> spop setredis 1 1) "4" 127.0.0.1:6379> smembers setredis 1) "2" 2) "3" 3) "5"集合的运算,我们在高中数学第一节课的时候就讲过集合(我们当时高中第一节讲的就是集合),不知道大家还记得交集并集补集都是什么意思吗?
sinter keyA keyB //集合keyA和集合B的交集,就是求既在集合A也在集合B内的元素
127.0.0.1:6379> sadd setA 1 2 3 4 5 6 (integer) 6 127.0.0.1:6379> sadd setB 5 6 7 9 10 (integer) 5 127.0.0.1:6379> sinter setA setB 1) "5" 2) "6"sinterstore destination keyA keyB //将交集的结果存在新的集合destination中
127.0.0.1:6379> SINTERSTORE newset setA setB (integer) 2 127.0.0.1:6379> smembers newset 1) "5" 2) "6"
sunion keyA keyB //得到集合A和集合B的并集结果
127.0.0.1:6379> SUNION setA setB 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 7) "7" 8) "9" 9) "10"sunionstore destination keyA keyB //将并集的结果存在新的集合destination中
sdiff keyA keyB //求集合A对于集合B的差集,也就是{A}-{B},更通俗一点说就是存在于集合A的,但是不存在于集合B的元素。
127.0.0.1:6379> smembers setA 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 127.0.0.1:6379> smembers setB 1) "5" 2) "6" 3) "7" 4) "9" 5) "10" 127.0.0.1:6379> sdiff setA setB 1) "1" 2) "2" 3) "3" 4) "4"sdiffstore destination keyA keyB //将差集的结果存在新的集合destination中
扩展:如果我们是sdiff keyA keyB keyC //这里就表示{A}-{B}-{C}。不要琢磨什么这是A对于B和C并集的差集...乱不乱,自己都懵圈的。
集合A:[1,2,3,4,5,6]
集合B:[2,3,4]
集合C:[5,7,9]
这时我们输入sdiff keyA keyB keyC他的返回应该是[1,6]。因为{A}-{B}为{1,5,6},在用这个集合去掉C包含的元素,也就是5,最终得到集合[1,6]
有序zSet常见操作
zadd key score member score member //往有序集合key中加入带score分值的元素
127.0.0.1:6379> zadd zsetredis 1 zhaor 2 qian (integer) 2zrem key member //从有序集合key中删除元素
127.0.0.1:6379> zrem zsetredis zhaor (integer) 1zscore key member //返回有序集合key中元素member的分值
127.0.0.1:6379> zscore zsetredis qian "2"zincrby key increment menber //为有序集合key中元素member的分值加上increment数值
127.0.0.1:6379> ZINCRBY zsetredis 10 qian "12"ZCARD key //返回有序集合key中的元素个数
127.0.0.1:6379> ZCARD zsetredis (integer) 2zrange key start stop withscores//正序获取有序集合内从 start到stop下标的元素,加了withscores展示分值
127.0.0.1:6379> zrange zsetredis 0 999 1) "zhao" 2) "qian"zrevrange key start stop withscores//倒序获取有序集合内从 start到stop下标的元素,加了withscores展示分值
127.0.0.1:6379> ZREVRANGE zsetredis 0 999 1) "qian" 2) "zhao"正序倒序都是按照分值来排序的
zSet运算
zunioonstore destkey numkeys keyA keyB //求集合A和集合B的并集
127.0.0.1:6379> ZUNIONSTORE newzset 2 zsetA zsetb (integer) 4 127.0.0.1:6379> ZRANGE newzset 0 1111 1) "wuliu" 2) "zhaogsan" 3) "wangwu" 4) "lisi"zinterstore destkey numkeys KeyA keyB //求集合A和集合B的交集,只看元素,不看分值。
127.0.0.1:6379> ZINTERSTORE newset 2 zsetA zsetb (integer) 1 127.0.0.1:6379> zrange newset 0 1111 1) "lisi"最进弄了一个公众号,小菜技术,欢迎大家的加入