什么是Redis?Redis是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,例如字符串、哈希、列表、集合、排序集合和范围查询、位图、hyperloglogs和地理空间索引半径查询。Redis还内置了复制、LUA脚本(Luascripting)、LRU驱动事件(LRUeviction)、事务(transactions)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(highavailability)。嗯,不错,这是redis中文官网上的介绍,简洁明了。什么是NoSQL我们知道redis是一种非关系型数据库NoSQL。为什么是NoSQL?什么是NoSQL?在单机数据库时代,当一个网站的访问量不多时,我们可以用一个数据库来处理流量请求。缓存+拆分随着流量的增加,一个数据库已经不能满足我们的需求了。为了更高的性能,我们在中间增加了一个缓存层,并对数据库进行了集群,优化了结构,实现了读写分离。这里的缓存是NoSQL。当然,缓存只是NoSQL的一个功能,就像Redis并不是只有缓存的功能一样。比如还可以实现简单的消息队列,解决session共享,计数器,排行榜,好友关系处理等功能。可见Redis是一个非常强大的工具,让我们一起学习吧!Redis常用命令首先我们先说说Redis的常用命令,不分数据类型。操作key和valueRedis是一个keyvalue存储的缓存数据库,所有的数据都有自己唯一的key。这里为了演示方便,我使用字符串相关的设置命令keys[pattern]来获取所有符合要求的key。时间复杂度为O(n),生产环境一般不使用,因为Redis是单线程的,执行耗时任务会阻塞其他任务。通常,将使用扫描命令代替(非阻塞)。dbsize获取当前存储的数据个数。existskey判断key是否存在delkey删除指定数据类型key获取指定key的数据类型renamekeynewkeyrenameexpirationtimeRedis中很多数据都是作为缓存数据使用的,作为缓存需要一个过期时间,在Redis中提供了非常强大的过期时间设置功能。expirekeyseconds设置密钥的过期时间。ttlkey查看某个key的剩余时间,返回一个正数表示剩余时间,-1表示永久,-2表示过期或不存在。Redis的五种基本数据类型上面提到了很多Redis作为缓存可以实现的其他功能,比如计数器、排行榜、好友关系等,这些实现的基础就是Redis的数据结构。Redis中有五种基本数据结构(后面还会讲到一些高级数据结构),它们是字符串、哈希、列表、集合和有序集合。String字符串在大多数编程语言中都有String字符串类型,对于Redis作为数据库来说也是必不可少的。setkeyvaluesetvaluegetkey获取某个key的值msetkey1value1key2value2批量设置,是原子的,可以用来减少网络耗时mgetkey1key2是批量获取的,是原子的,可以用来减少网络耗时incrkey增加指定key的值decrkey减少指定key的值incrbykeyvalue增加指定的值decrbykeyvalue减少指定的值incrbyfloatkeyfloatvalue增加指定的浮点数,前面的操作都可以用于实现计数器的功能。setnxkeyvalue如果key不存在,可以设置成功,否则会失败,加上过期时间限制,是redis实现分布式锁的一种方式(后面会提到)。setkeyvaluexx与前面相反,如果存在则设置成功,否则失败(相当于更新操作)hash其实我们可以理解为hash是一个小型的Redis,Redis的底层实现类似到Java中的HashMap,都是采用数组+链表的二维结构实现的。不同的是Redis中字典的值只能是字符串,它们的rehash方式不同。在Redis中,使用了渐进式重新散列。在rehash期间,旧的和新的哈希字典将被保留。数据迁移时,旧字典的内容会一点一点迁移到新字典中。查询时会同时查询这两个哈希字典,直到迁移完所有数据后才会释放数据。将用新词典替换旧词典。我们先看一下hash的基本操作。hsetkeyfieldvalue设置字典中某个key的值hsetnxkeyfieldvalue设置字典中某个key的值(不存在)hmsetkeyfield1value1field2value2...sethgetkeyfield批量获取值字典中的一个keyhmgetkeyfield1field2批量获取hgetallkey获取所有hdelkeyfields删除某个keyhexistskeyfield判断hlenkey是否存在获取指定key对应的字典中存储数hvalskey返回所有值hkeyskey返回所有keyshincrbykeyfieldincreValue增加某个value的值(也可以加负数)hincrbyfloatkeyfieldfloatValue增加一个value的值(浮点数)listRedis中的list相当于LinkedList(双链表)在Java中,即底层是通过链表实现的,所以对于链表来说插入和删除很快,但是索引定位很慢。Redis提供了很多对list的操作,比如输出、输入等操作,你可以充分利用它们来实现一个栈或者队列。让我们看一下列表的基本操作。lpushkeyitem1item2item3...从左边压入rpushkeyitem1item2item3...从右边压入lpopkey从左边弹出rpopkey从右边弹出lindexkeyindex获取指定索引的元素O(n)小心使用lrangekeystartend获取指定范围的元素O(n)小心使用count=0:删除所有value元素count>0:从左到右删除count个有value的元素count<0:从右到|删除计数|linsertkeybefore|afteritemnewitem在指定元素之前或之后添加一个新元素lremkeycountvalue删除指定值元素ltrimkeystartend保留指定范围的元素lsetkeyindexnewValue更新某个索引的值blpopkeytimeout没有超时则阻塞(timeout指定阻塞时间为0代表永久)brpopkeytimeout不阻塞(timeout指定阻塞时间为0代表永久)这两个可以用来实现consumer生产者。我们可以用左进左出或者右进左出来实现队列,左进左出或者右进右出来实现栈。setRedis中的set相当于Java中的HashSet(无序集合)。里面的元素不能重复。我们可以用它来实现一些去重功能。我们还对几个集合进行交集、并集等操作,这些操作可以获取不同用户之间的共同朋友、共同爱好等。让我们看一下现场的一些基本操作。saddkeyvalue添加一个元素sdelkeyvalue删除一个元素sismemberkeyvalue判断是否是集合中的元素srandmemberkeycount随机获取指定数量的元素(不会影响集合结构)spopkeycount从集合中随机弹出元素collection(会破坏组合结构)smemberskey获取集合的所有元素O(n)复杂度scarkey获取集合的个数sinterset1set2...获取所有集合的交集sdiffset1set2...获取差值ofallsetssunionset1set2...获取所有集合zset中的联合集合zset在Redis中是一个有序集合,通过它可以实现很多有趣的功能,比如学生成绩排行榜,视频播放量排行榜等等。Zset是使用跳表实现的。我们知道只有数组的连续空间可以使用二分查找来快速定位,而链表是不行的。跳表有助于在查找链表时节省大量时间(使用跳转方式遍历索引进行有序插入),如果不知道跳表可以看教程。Redis中的事务和pipeline管道在某些场景下,我们可能需要在一次操作中执行多条命令。如果我们只执行一条命令一条命令,会浪费大量的网络时间。如果将命令传输到Redis中重新执行会减少很多开销时间。但需要注意的是,管道中的命令并不是原子执行的,这意味着管道中的命令在到达Redis服务器时可能会被其他命令穿插。事务关系数据库具有ACID特性。Redis可以保证A(原子性)和I(隔离性),D(持久性)看是否配置了RDB或者AOF持久化操作,但是不能保证一致性,因为Redis事务不支持回滚。我们可以简单的理解为Redis中的事务只是比Pipeline多了一个原子操作,即不会被其他命令分割,如上图所示。多交易开始的标志。exectransactionexecutiondiscard清除本次事务中放入队列的所有命令,即取消整个事务。监视键在事务开始之前监视一个元素。如果在提交事务时发现该元素的值被其他客户端更改,则事务将失败。unwatchkeyunmonitorRedis常用命令汇总
