Redis详细介绍
Redis
NoSQL:Not Only SQL,是非关系型数据库;
Web2.0对于上万次的读写,关系型数据库的压力是非常大的;
因此NoSQL非关系型的数据库应运而生;
为什么需要NoSQL?
High performance高并发读写
Huge Storage海量数据的高效率存储和访问
High Scalability&&High Avaliability高可扩展性和高可用性
NoSQL的主流产品:
mongoDB,Redis,CouchDB,riak,Cassandra等等;
NoSQL数据库的四大分类
1. 键值对存储(Key-Value)
比如:Redis可以进行键值对存储数据;可以快速查询,但是存储的数据缺少结构化
2. 列存储
比如:HBase就是列存储数据库,查找速度快,可扩展性强,功能相对于局限;
3. 文档数据库
比如:MongoDB,数据结构要求不是特别的严格,查询性能不是特别高,缺少统一的查询语法;
4. 图形数据库
应用于社交网络,利用图结构的相关算法;需要对整个图进行计算才能得出结果;
NoSQL的特点:易扩展,数据库之间没有关系;灵活的数据模型;数据量大,高可用;
Redis
Redis是高性能的键值对数据库,支持的键值对数据类型有:
字符串类型,散列类型,列表类型,集合类型,有序集合类型;
50个并发程序执行10万次请求,读的速度:11万次每秒,写的速度8万次每秒;
Redis的应用场景:缓存,一些新闻和商品的内容,我们都需要把这些数据放到缓存中;聊天室的在线好友列表;任务队列秒杀,抢购等等;网站访问统计,数据过期处理,应用排行榜,分布式集群架构中的session分离等等;
Redis 安装
Window 下安装
下载地址:https://github.com/MSOpenTech/redis/releases。
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 C 盘,解压后,将文件夹重新命名为 redis。
注意:如果想要进入某个文件夹cmd,就直接在某个文件夹上面的框框中cmd回车即可;
例如:当前是在redis的文件夹里面,直接cmd回车就可以;
打开一个 cmd 窗口 使用cd命令切换目录到 C:edis 运行 redis-server.exe redis.windows.conf 。
如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:
这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。
切换到redis目录下运行 redis-cli.exe -h 127.0.0.1 -p 6379 。
设置键值对 set myKey abc
取出键值对 get myKey
Linux 下安装
下载地址:http://redis.io/download,下载最新文档版本。
本教程使用的最新文档版本为 2.8.17,下载并安装:
$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar xzf redis-2.8.17.tar.gz
$cdredis-2.8.17
$make
make完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:
下面启动redis服务.
$cdsrc
$./redis-server
注意这种方式启动redis 使用的是默认配置。也可以通过启动参数告诉redis使用指定配置文件使用下面命令启动。
$cdsrc
$./redis-server redis.conf
redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了。 比如:
$cdsrc
$./redis-cli
redis>setfoo bar
OK
redis>getfoo"bar"
Ubuntu 下安装
在 Ubuntu 系统安装 Redi 可以使用以下命令:
$sudoapt-getupdate
$sudoapt-getinstall redis-server
启动 Redis
$redis-server
查看 redis 是否启动?
$redis-cli
以上命令将打开以下终端:
redis127.0.0.1:6379>
127.0.0.1 是本机 IP ,6379 是 redis 服务端口。现在我们输入 PING 命令。
redis127.0.0.1:6379>ping
PONG
以上说明我们已经成功安装了redis。
Redis的安装和使用(略)
Jedis
Jedis是redis的连接的基本操作;Redis不仅使用命令操作;基本上主流的开发语言都支持redis客户端的操作;通过官网查看相应的客户端;https://redis.io/clients
Jedis是Redis官方首选的java客户端开发包;Redis已经把Jedis托管到github上面了;
Jedis的下载地址:https://github.com/xetorthio/jedis
Jedis保存数据:jedis.set(“key”,”value”);
Jedis获取数据:jedis.get(“key”);
Jedis和jdbc类似,也可以使用连接池来获取数据;
比较常用是字符串String和哈希hash;
Redus是一个以key,value键值对的数据库;
Key的定义:不要太长,最好不要超过1024个字节,不仅会消耗内存,还会降低查询效率;不要太短;统一的命名规范;
存储字符串String,以二进制的形式来存储的;
存储字符串的常用命令:
set company imooc
表示:保存数据,将key的值imooc保存在company中;
get company
表示:取出数据,将company中的值取出来,得到的是imooc
del company
表示: 删除company中的值imooc,得到的是(integer)1
get company
表示:company中的值imooc已经删除了,此时已经拿不到imooc了,所以得到的是(nil)
incr num
表示:首先数据库redis中没有num,incr num会先将num的值赋值为0,然后加1;得到的结果是(integer)1;
incr num
表示:此时数据库redis中有了num,值为1,然后执行incr num表示经num的值加1,所以num的是为2;
get num
表示:获取num的值,值为2;
decr num2
表示:数据库redis中没有num2的值,数据库会先将num2的值赋值为0,然后再执行减1的操作,结果为(integer)-1;
incrby num 5
表示:将num的值加5,如果数据库redis中没有num,那么执行完incrby num 5结果是5;
decrby num 3
表示:将num的值减去3,结果为2;如果数据库redis中之前没有num,那么结果为-3;
append num 5
表示:在num的值后面追加字符5;如果num之前有值是3的话,那么get num的结果为”35”;那么 append num 5的结果为(integer)2,因为是字符串的长度;
Redis的数据结构的第二种:Hash存储
Redis中的hash可以看做是一种String的key和String的value的map容器;
非常适合存储值对象的信息, 比如存储用户名密码,姓名年龄等;如果hash中包含了很少的字段,那么这个类型的数据也将占有很少的磁盘空间;每一个hash可以存储很多个键值对;
hset和hmset存值;
hset myhash username jack
说明:hset命令进行设置,key是myhash,键值对是username jack;表示往里面去存值,结果为:(integer)1
hset myhash age 18
说明:hset命令进行设置,key是myhash,键值对是age 18;表示往里面去存值,结果为:(integer)1
hmset myhash2 username rose age 21
说明:hmset可以一起设置多个key和value;key是myhash2,键值对是:username rose和age 21;
hget取值
hget myhash username
说明:hget取值,取的key是myhash,要取的值是username中的内容;结果是jack
hmget myhash username age
说明:hmget获取多个属性的值;取的是username和age中的值,结果为:jack 18
hgetall hash
说明:hgetall表示获取key中所有的属性和属性的值;这里的结果是username jack age 18
hdel删除和del删除
hdel myhash2 username age
说明:hdel表示删除myhash2中的username和age的属性,结果为(integer)2
hgetall myhash2
说明:表示获取key为myhash2中的所有的属性和属性的值,结果为(empty list or set)表示是空的,获取不到
hdel myhash2 username
说明:此时myhash2中已经没有值了,删除失败;所以结果是(integer)0
hset myhash2 username rose age 21
说明:往myhash2中存值;
del myhash2
说明:删除myhash2中的属性和属性值,结果为:(integer)1
hget myhash2 username
说明:取属性为username中的值,结果为nil,表示没有取到,应为之前已经被删除了;
hget myhash age
说明:取出age属性中的值,结果为18;
hincrby myhash age 5
说明:hincrby表示为某个属性增加数字;这里表示为age的属性值增加5;
hget myhash age
说明:取出age中的属性值,结果为23;
hexists myhash username
说明:hexists判断myhash中的username属性的值是否存在,存在就返回1,不存在就返回0;和结果是1;
hexists myhash password
说明:myhash中的password属性不存在,所以返回结果是0;
hlen myhash
说明:表示获取myhash中的属性有几个,结果是(integer)2
hkeys myhash
说明:获取所有的key,结果是username age
hvals myhash
说明:获取myhash中所有的值,结果是jack 23
Redis的数据结构的第三种:list存储
Redis中list的数据类型是按照插入顺序排序的一个字符串链表;和数据结构中的普通的链表是一样的;可以在头部(左侧)和尾部(右侧)去添加新的元素,在插入的时候,如果该键不存在,Redis就会为该键创造一个新的链表;如果链表中的所有元素搜被移除了,那么该键也会被数据库库删除;从元素插入和删除的视角来看呢,如果是在链表的两头插入和删除元素,这是非常高效的操作;如果链表中已经存在了百万条记录,从链表的两头插入和删除元素也是可以高效的完成;注意:如果元素的插入和删除是作用在链表的中间,那么这个时候的效率会比较低;
存储list方式
ArrayList使用数组的方式存储数据,很具索引去查询的速度是非常快的,但是新增和删除元素的时候需要涉及到位移操作,所以会比较慢;
LinkedList使用双向链接方式,每个元素都记录了前后元素的指针,插入和删除数据的时候只是改变了前后元素的指针所指向即可,速度都非常快;
双向链表中添加数据
双向链表中删除数据
lpush mylist a b c
说明:lpush表示从左侧向链表中添加数据,mylist表示key,
a b c表示往链表中放入数据,a是先进去的,在后面,b在中间,c最后进去的在最外边儿,在最左侧;结果为:(integer)3
lpush mylist 1 2 3
说明:从左侧向链表中插入数据;结果为:(integer)6
rpush mylist2 a b c
rpush mylist2 1 2 3
说明:rpush表示从右侧向链表中添加数据;结果为:(integer)6
lrange mylist 0 5
说明:lrange表示查看链表,mylist为想要查看的链表,后面的为从0开始到5结束;可以从0开始计数,也可以从负数开始计数,如果是-1表示是链表尾部的元素;-2则表示倒数第二个元素;命令的结果为:3 2 1 c b a
lrange mylist2 0 -1
说明:查看mylist2链表中的元素:从第0个到倒数第一个,结果是:a b c 1 2 3
lrange mylist2 0 -2
说明:查看mylist2链表中的元素:从第0个到倒数第二个,结果是:a b c 1 2
lpop mylist
说明:lpop表示从左边儿(头部)弹出,mylist为key,它会返回并弹出指定的key所关联的链表中的第一个元素,也就是它的头部元素;如果您不存在就会返回nil,如果存在就会返回第一个元素;mylist中的第一个元素是3,所以3就会被弹出来,结果为:3
lrange mylist 0 -1
说明:查看链表mylist中的元素,从第0个到倒数第一个;结果为:2 1 c b a
因为3已经被弹出了
rpop mylist2
说明:rpop表示从尾部(右边)弹出;也是3杯弹出了,结果为3
lrange mylist2 0 -1
说明:查看链表mylist2中的元素,从第0个到倒数第一个,结果为:a b c 1 2因为2已经被弹出了;
llen mylist
说明:llen表示获取链表中元素的个数;结果为5
llen mylist3
说明:因为链表mylist3是没有的链表,所以结果为(integer)0
lpushx mylist x
说明:lpushx表示仅当参数中指定的key存在的时候,可以向关联的链表的头部插入一个具体的值,如果key不存在就不会插入了;结果为:(integer)6
lrange mylist 0 -1
说明:查看链表mylist中的元素,从第0个到倒数第一个,结果为:x 2 1 c b a
lpushx mylist3 x
说明:mylist3这个key不存在,所以结果是(integer)0
rpushx mylist2 y
说明:key存在的时候,向关联的链表的尾部插入一个具体的值,key不存在就不插入了;这里的key存在,结果是(integer)6
lrange mylist2 0 -1
说明:查看链表mylist2中的元素,从第0个到倒数第一个,结果为:a b c 1 2 y
lrem mylist
说明:lrem mylist后面跟上一个count value,该指令会删除count个为value的元素; 如果count大于0,从头向尾遍历并删除count个为value的元素;如果count小于0,从后面向前面去遍历;如果count等于0,删除链表中所有等于某个值的元素;
lpush mylist3 1 2 3
说明:往链表中插入1 2 3结果是(integer)3
lpush mylist3 1 2 3
说明:说明:往链表中插入1 2 3结果是(integer)6
lpush mylist3 1 2 3
说明:说明:往链表中插入1 2 3结果是(integer)9
lrange mylist3 0 -1
说明:查看mylist3链表里面的元素,结果为3 2 1 3 2 1 3 2 1
lrem mylist3 2 3
说明:lrem mylist3表示删除链表mylist3中的2个3的元素,2大于0,从头往尾删除2个为3的元素,结果为(integer)2
lrange mylist3 0 -1
说明:查看mylist3中的元素;结果为:2 1 2 1 3 2 1
lrem mylist3 -2 1
说明:-2小于0,从链表的尾部删除元素值为1 的元素,删除2个,结果为(integer)2
lrange mylist3 0 -1
说明:查看链表中的元素,结果为:2 1 2 3 2
lrem mylist3 0 2
说明:删除mylist3里面的所有的元素值为2的元素;结果为:(integer)3
lrange mylist3 0 -1
说明:查看链表中的所有的元素,结果为:1 3
lset
说明:lset设置链表中的某个index的脚标的元素的值;0代表第一个元素,-1代表最后那一个元素,不存在就抛出异常;
lrange mylist 0 -1
说明:查看mylist中的所有的元素,结果为:x 2 1 c b a
lset mylist 3 mmm
说明:往链表mylist中的下标(也叫脚标)为3的元素c的值设置为mmm,结果为OK
lrange mylist 0 -1
说明:查看链表mylist中的所有的元素的,结果为:x 2 1 mmm b a表示c被替代了;
lpush mylist4 a b c
说明:往mylist4中放入a b c元素,结果为:(integer)3
lpush mylist4 a b c
说明:往mylist4中放入a b c元素,结果为:(integer)6
lrange mylist4 0 -1
说明:查看mylist4中的所有的元素,结果为:c b a c b a
linsert mylist4 before b 11
说明:表示往b元素之前插入11的值,结果为(integer)7
注意:之前用before,之后用after
lrange mylist4 0 -1
说明:查看mylist4中所有的元素,结果为:c 11 b a c b a
lrem mylist3 0 2
说明:删除mylist3中的所有的2
lrange mylist3 0 -1
说明:查看mylist3中的所有的元素,结果为1 3
lset
说明:lset设置链表中的某个index的脚标的元素的值,0代表第一个元素,-1代表最后一个元素,脚标不存在就会抛出异常;
lrange mylist 0 -1
说明:查看mylist链表中的所有的元素,结果为:x 2 1 c b a
lset mylist 3 mmm
说明:在mylist链表中设置第3个脚标的值为mmm,也就是将c改成mmm
lrange mylist 0 -1
说明:查看mylist中的所有的元素,结果为:x 2 1 mmm b a
lpush mylist5 1 2 3
说明:往mylist5链表中放入3个元素,结果为:(integer)3
lpush mylist6 a b c
说明:往mylist6链表中放入3个元素,结果为:(integer)3
lrange mylist6 0 -1
说明:查看mylist6中的所有的元素,结果为c b a
rpoplpush mylist5 mylist6
说明:rpoplpush表示从mylist5链表(3 2 1)中从右边开始弹出1个元素,然后从左边放入mylist6(c b a)中,结果为1
lrange mylist5 0 -1
说明:查看mylist5链表中的所有的元素;结果为:3 2
lrange mylist6 0 -1
说明:查看mylist6链表中的所有的元素;结果为:1 c b a
redis经常用于消息队列的消息服务,完成多个程序之间的消息交互;假设一个应用程序正在使用lpush向链表中添加新的元素,通常将这样的程序称为生产者,另一个程序正在使用rpop操作,从链表中取出元素,称为消费者;消费者程序在取出元素后崩溃,由于该消息已经被取出且没有被正常处理,我们认为这个消息已经丢失了,由此可能导致业务数据的丢失,或者导致业务状态的不一致等现象的发生,可以通过rpop,lpush这个命令,消费者程序在主消息队列中取出元素之后,再将它插入到一个备份的队列中,直到消费者程序完成正常的逻辑处理后,再讲消息从备份队列中删除,这样的话,我们可以提供一个守护的线程,当发现备份消息队列过期的时候,可以重新将它放到主消息的队列中,以便其他的消费者可以继续去处理;
Redis的数据结构的第四种:set存储
在redis中,可以将Set类型看做成没有排序的字符集合,和List类型一样;可以在该类型的数据值上执行添加,删除,判断某一个元素是否存在的操作;Set集合中不允许出现重复的元素,Set可包含的最大元素数量是4294967295;
sadd myset a b c
说明:往Set中添加元素a b c;结果为(integer)3
sadd myset a
说明:再往Set中添加元素a,这时是添加失败的,因为a元素已经存在了;
sadd myset 1 2 3
说明:往myset中添加元素 1 2 3,结果为(integer)3
srem myset 1 2
说明:删除myset中的1和2元素;结果为:(integer)2
smembers myset
说明:查看myset中的元素,结果为:c b a 3
sismember myset a
说明:查看元素a是否在myset中,如果存在就返回1,不存在就返回0;
sismember myset x
说明:查看元素x是否在myset中,结果是:(integer)0
集合的差集运算sdiff key1 key2
说明:集合的差集运算,返回集合中相差的成员,而且与key的顺序是有关系的;
sadd mya1 a b c
说明:往mya1中添加3个元素a b c
sadd myb1 a c 1 2
说明:往myb1中添加4个元素a c 1 2
sdiff mya1 myb1
说明:求集合mya1和myb1的差集(与顺序有关),结果是:b
sadd mya2 a b c
说明:往集合mya2中添加元素a b c
sadd myb2 a c 1 2
说明:往集合myb2中添加元素a c 1 2
sinter mya2 myb2
说明:sinter为求两个集合中都有的部分,结果为a c
sadd mya3 a b c
说明:往集合mya3中添加元素a b c
sadd myb3 a c 1 2
说明:往集合myb3中添加元素a c 1 2
sunion mya3 myb3
说明:sunion为求两个几个的并集;结果为:c 2 b a 1
smembers myset
说明:查看myset中的元素;结果为:c b a 3
scard myset
说明:查看myset中的元素的个数,结果为(integer)4
srandmember myset
说明:srandmember随机的返回set中的一个成员;
sdiffstore my1 mya1 myb1
说明:将两个集合相差的元素存储到一个新的集合,将mya1和myb1中相差的部分存储到新的集合my1中;结果为:(integer)1
smembers my1
说明:查看集合my1的元素,结果为b;
sinterstore
说明:求两个集合的交集,然后存储在一个新的集合中;
sinter mya2 myb2
说明:求两个集合的交集,结果为c a
sinterstore my2 mya2 myb2
说明:将集合mya2和myb2的交集存储在新的集合my2中;
smembers my2
说明:查看my2集合中的元素,结果为c a
sunion mya3 myb3
说明:查看集合mya3和myb3的并集的结果;
sunionstore my3 mya3 myb3
说明:将集合mya3和myb3的并集存储在一个新的集合my3中;
smembers my3
说明:查看my3中的所有的元素,结果为:c 2 b a 1
Set的具体使用场景:可以使用Redis的Set数据类型跟踪一些具有唯一性的数据;比如:访问某一博客的唯一ip地址的信息,在每次访问该博客的时候将访问者的ip存入到redis中,Set的数据类型就会自动保证ip地址的唯一性;还可以充分利用Set类型的服务器端聚合操作的方便高效的一些特性可以用于维护数据对象之间的一些关联关系;比如所有购买某一个电子设备的客户的id,被指定存储到一个指定的Set中,而购买另外一种电子设备的id被存储到了另外一个Set中,如果此时需要获取有哪些客户同时购买了这两种商品,这个时候使用这两个Set的交集就可以了;
Redis的数据结构的第五种:Sorted-Set存储
Sorted-Set不允许集合中出现重复的元素,Sort-Set中的每一个成员都会有一个分数与之关联;Redis就是通过这个分数来为集合中的成员进行从小到大的一个排序,尽管Sorted-Set中的成员必须是唯一的,但是分数却是可以重复的;Sorted-Set中添加,删除,更新一个成员都是非常快的操作;它的时间复杂度是集合中成员的个数的对数,由于Sorted-Set中的成员在集合中的位置是有序的的,即使是访问集合中间的成员也是非常高效的;
Sorted-Set的常用命令
zadd mysort 70 zs 80 ls 90 ww
说明:zadd为添加,mysort为key,每一个元素都有一个分数,70,80,90都为分数;zs,ls,ww分别为分数对应的元素;返回的是存到集合中的个数;结果为:(integer)3
zadd mysort 100 zs
说明:添加元素zs,如果已经存在了元素zs,那么会用新的分数100去替换原有的分数70;返回结果是:(integer)0因为之前有zs元素了,所以不显示;还是0;
zadd mysort 60 tom
说明:往mysort中新添加tom元素,结果为:(integer)1
zscore mysort zs
说明:zscort表示获取元素的的分数,结果为100
zcard mysort
说明:zcard获取mysort中的成员的数量,结果是(integer)4
zrem mysort tom ww
说明:zrem删除mysort中的tom和ww元素,结果为:(integer)2
zcard mysort
说明:zcard查看mysort中的元素的个数;结果为:(integer)2
zadd mysort 85 jack 95 rose
说明:往mysort中添加2个元素,jack和rose
zrange mysort 0 -1
说明:查看mysort中的所有的元素,结果为:ls jack rose zs
zrange mysort 0 -1 withscores
说明:查看mysort中所有的元素和分数;结果为:ls 80 jack 85 rose 95 zs 100;
zrevrange mysort 0 -1 withscores
说明:zrevrange从大到小查看mysort中的元素和分数;结果为:zs 100 rose 95 jack 85 ls 80
zremrangebyrank mysort 0 4
说明:按照范围进行删除,结果为(integer)4
zadd mysort 80 zs 90 ls 100 ws
zremrangebyscore mysort 80 100
说明:按照分数的范围进行删除,删除分数为80到100之间的元素;结果为:(integer)3
zrange mysort 0 -1
说明:查看mysort中的所有的元素,结果为:(empty list or set)
zadd mysort 70 zs 80 ls 90 ww
zrangebyscore mysort 0 100 withscores
说明:查看mysort中分数为0到100之间的元素,结果为:zs 70 ls 80 ww 90
zrangebyscore mysort 0 100 withscores limit 0 2
说明:查看mysort中的分数为0到100的元素中的2个元素和分数;结果为:zs 70 ls 80
zincrby mysort 3 ls
说明:设置指定成员ls增加的分数3;结果为:83
zscore mysort ls
说明:查看mysort中ls元素的分数,结果为83
zcount mysort 80 90
说明:查看分数在80到90之间的元素的个数,结果为(integer)2
Sorted-Set的使用场景:使用于大型网络游戏的积分排行榜;当玩家的分数发生变化的时候,可以使用zadd更新玩家的分数,然后通过zrange来获取积分;Sorted-Set可以用于构建索引数据;
Keys的通用操作
keys *
说明:查看所有的key
keys my?
说明:查看以my开头的所有key
del my1 my2 my3
说明:删除某个指定的key;删除my1和my2和my3的key;
exist my1
说明:查看某个key是否存在,如果存在就返回1,不存在就返回0;
get company
说明:获取key等于company的值;比如:结果为:baidu
rename company newcompany
说明:重命名key的名字,将key的名字改为newcompany
get company
说明:获取key等于company的值,此时的company已经不存在了,被改名字了,所以结果是(nil)
get newcompany
说明:获取key等于newcompany的值,结果是baidu
expire newcompany 1000
说明:设置key的过期时间,1000秒;
ttl newcompany
说明:查看key离超时还剩的时间;比如结果为:967;注意:如果没有设置key的超时时间,就会返回-1;
type newcompany
说明:查看key的类型;比如:结果为string
Redis的特性
Redis多数据库,Redis支持事务;
一个Redis的实例可以包含多个数据库;客户端可以指定连接某个Redis实例的哪个数据库;就好比是mysql中创建多个数据库一样,客户端连接的时候可以指定连接哪个数据库;一个Redis实例最多可以提供16个数据库;下标分别是熊0到15,客户端默认的连接是第0号数据库;也可以通过select来选择具体连接哪个数据库;
select 1
说明:连接1号数据库
keys *
说明:查看该数据库中的所有的key,结果是(empty list or set)
select 0
说明:连接0号数据库
keys *
说明:查看0号数据库的所有key,结果为:mylist2 myset mya1
move myset 1
说明:将myset这个key从0号数据库移到1号数据库;
select 1
说明:选择1号数据库
keys *
说明:查看1号数据库中的所有的key,结果为:myset;刚从0号数据库移过来的;
select 0
说明:选择0号数据库;
Redis中的实现事务的命令:multi和exec和discard;
在事务中,所有的命令将串行化,顺序执行;在事务执行的过程中,redis不会在为其他的数据库客户端提供任何的服务,从而保证事务中所有的命令都被原子化,和关系型数据库相比,在redis中,如果某一个命令执行失败了,后面的命令还是会被执行;
multi可以开启一个事务;后面的命令都将会被存到队列中,直到执行exec命令;
exec提交事务,
discard回滚
在事务开启之前,如果客户端和服务器之间出现通讯故障并导致网络断开;事务中的语句都将不会被服务器执行;如果网络中断发生在客户端执行之后的,那么事务中的所有命令都将会被服务器执行;
打开新的窗口
连接redis:cd /usr/local/redis
查看:ll
开启redi的客户端./bin/redis-cli
清空:clear
Redis的持久化
Redis所有的数据都存储在内存中;为了使redis在重启之后仍然能保证数据不丢失,那么就需要将数据从内存中同步到我们的硬盘上,这个过程我们称之为持久化;
Redis的持久化的方式;
RDB持久化:RDB的方式是默认支持的,不需要配置的,在指定的时间间隔内,将内存中的数据写到磁盘一次;可以指定30秒,50秒等等;
AOF持久化:以日志的形式记录服务器所处理的每一个操作,在redis服务器启动之初,AOF会读取该文件,重新构建数据库,这样保证启动后,数据是完整的;
无持久化:通过配置禁用redis的服务器的持久化的功能;这时的redis就是一个缓存的功能;
同时使用RDB和AOF的方式:
Redis持久化的RDB的方式;
RDB方式:一旦采用了RDB方式,整个Redis数据库将只包含一个文件,那么对于文件备份而言,是非常完美的;比如打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据,可以通过RDB方式的策略,一旦系统出现灾难性的故障,可以进行非常容易的进行恢复;对于灾难恢复而言,RDB是非常不错的选择,可以非常轻松的将一个单独的文件压缩后,再将它转移到其他的存储介质上,可以将它拷贝走,然后恢复的时候再把它拿出来;性能最大化,对于Redis的服务进程而言,在开始持久化的时候,它唯一需要做的是分叉出一些进程,然后由子进程完成持久化的工作,这样可以极大的避免服务器进程执行IO的操作;相比AOF的机制,如果数据集很大,RDB的启动效率会很高,整死RDB的优势,RDB的缺点:如果想要保证数据的高可用性,就是最大的限度避免数据的丢失,RDB将不是一个很好的选择,因为系统一定在定时持久化之前,出现一些宕机的情况,还没来得及往硬盘上面写,数据就丢失了;比如说30秒往硬盘上面写一次;当到了25秒的时候,服务器可能发生了宕机;还没来得及往硬盘上面去写内容的时候;那么前25秒的数据就没有了;RDB通过fork分叉的方式子进程来协助完成数据持久化工作的,因此当如果数据集非常大的时候,可能会导致服务器会停止几百毫秒甚至更长的时间;
RDB方式的配置:
cd /usr/local/redis
说明:比如进入到redis的路径下,
ll
说明:查看redis中的文件,比如有redis.conf文件;
vim redis.conf
说明:打开redis.conf的配置文件;
比如:save 900 1表示:每过900秒至少有1个key发生变化,和这个时候会持久化(持久化也就是往硬盘上写一次内容)1次;
Redis的AOF持久化的方式
AOF机制可以带来更高的数据安全性;
Redis提供了3种同步策略,每秒同步,每修改同步,不同步;
每秒同步:也是异步的,效率是非常高的;一旦系统出现宕机情况,这一秒钟修改的数据就会丢失;
每修改同步:可以视为同步持久化,每一次发生数据的变化,都会被立即的记录在磁盘中,这种效率是最低的;但是它是最安全的;
对于日志的操作采用的是append的模式,追加的模式;因此即使出现宕机的情况下,也不会破坏日志文件中已经存在的内容;然而如果本次操作只是写入了一半的操作,就出现了系统崩溃的问题;在Redis下一次启动之前,Redis-check-aof可以帮助解决数据一致性的问题;如果日志过大,Redis可以自动启动重写机制,Redis采用append的机制不断的将修改的数据写入到老的磁盘中,同时,redis还会创建一个新的文件用于记录此期间产生了哪些修改命令被执行了,因此在执行重写切换的时候;可以更好的保证数据的安全性;
AOF包含一个格式非常清晰的易于理解的日志文件用于记录所有的修改操作;
对于相同的数量的数据集而言,AOF文件比RDB的文件大一些,根据同步策略不同,AOF在运行的效率上比RDB低;
AOF的配置;
vim redis.conf
说明:打开redis.conf文件;
可以看到appendonly no
因为redis默认使用的是RDB的方式;
当然如果想要使用AOF的方式,可以将appendonly no改为appendonly yes的方式;这个时候会产生一个appendonly.aof的文件;
以下是3中同步策略:
appendsync always表示每修改一次都会同步到磁盘上,
appendsync everysec表示每秒钟往硬盘上写一次;
appendsync no表示不同步
wq表示保存文件;
./bin/redis-cli表示连接redis客户端;
./bin/redis-cli shutdown表示断开redis客户端;
shutdown表示断开;
./bin/redis-server ./redis.conf表示重新启动redis服务
clear表示清除屏幕
客户端操作实例:
set name jack
set num 10
set n1 12
说明:存入一些数据
keys *
说明:查看所有的key,结果为:n1 num name
flushall
说明:清空数据库里面的内容;
keys *
说明:查看数据库里面所有的key,结果为empty list or set,应为已经flushall了;
NoSQL:Not Only SQL,是非关系型数据库;
Web2.0对于上万次的读写,关系型数据库的压力是非常大的;
因此NoSQL非关系型的数据库应运而生;
为什么需要NoSQL?
High performance高并发读写
Huge Storage海量数据的高效率存储和访问
High Scalability&&High Avaliability高可扩展性和高可用性
NoSQL的主流产品:
mongoDB,Redis,CouchDB,riak,Cassandra等等;
NoSQL数据库的四大分类
1.键值对存储(Key-Value)
比如:Redis可以进行键值对存储数据;可以快速查询,但是存储的数据缺少结构化
2.列存储
比如:HBase就是列存储数据库,查找速度快,可扩展性强,功能相对于局限;
3.文档数据库
比如:MongoDB,数据结构要求不是特别的严格,查询性能不是特别高,缺少统一的查询语法;
4.图形数据库
应用于社交网络,利用图结构的相关算法;需要对整个图进行计算才能得出结果;
四类NoSQL数据库比较
Redis是高性能的键值对数据库,支持的键值对数据类型有:
字符串类型,散列类型,列表类型,集合类型,有序集合类型;
50个并发程序执行10万次请求,读的速度:11万次每秒,写的速度8万次每秒;
Redis的应用场景:缓存,一些新闻和商品的内容,我们都需要把这些数据放到缓存中;聊天室的在线好友列表;任务队列秒杀,抢购等等;网站访问统计,数据过期处理,应用排行榜,分布式集群架构中的session分离等等;
Redis 安装
Window 下安装
下载地址:https://github.com/MSOpenTech/redis/releases。
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载Redis-x64-xxx.zip压缩包到 C 盘,解压后,将文件夹重新命名为redis。
注意:如果想要进入某个文件夹cmd,就直接在某个文件夹上面的框框中cmd回车即可;
例如:当前是在redis的文件夹里面,直接cmd回车就可以;
打开一个cmd窗口 使用cd命令切换目录到C:edis运行redis-server.exe redis.windows.conf。
如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:
这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。
切换到redis目录下运行redis-cli.exe -h 127.0.0.1 -p 6379。
设置键值对set myKey abc
取出键值对get myKey
Linux 下安装
下载地址:http://redis.io/download,下载最新文档版本。
本教程使用的最新文档版本为 2.8.17,下载并安装:
$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar xzf redis-2.8.17.tar.gz
$ cd redis-2.8.17
$ make
make完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:
下面启动redis服务.
$ cd src
$ ./redis-server
注意这种方式启动redis 使用的是默认配置。也可以通过启动参数告诉redis使用指定配置文件使用下面命令启动。
$ cd src
$ ./redis-server redis.conf
redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了。 比如:
$ cd src
$ ./redis-cli
redis>set foo bar
OK
redis>get foo"bar"
Ubuntu 下安装
在 Ubuntu 系统安装 Redi 可以使用以下命令:
$sudo apt-get update
$sudo apt-get install redis-server
启动 Redis
$ redis-server
查看 redis 是否启动?
$ redis-cli
以上命令将打开以下终端:
redis 127.0.0.1:6379>
127.0.0.1 是本机 IP ,6379 是 redis 服务端口。现在我们输入 PING 命令。
redis 127.0.0.1:6379> ping
PONG
以上说明我们已经成功安装了redis。
Redis的安装和使用(略)
Jedis
Jedis是redis的连接的基本操作;Redis不仅使用命令操作;基本上主流的开发语言都支持redis客户端的操作;通过官网查看相应的客户端;https://redis.io/clients
Jedis是Redis官方首选的java客户端开发包;Redis已经把Jedis托管到github上面了;
Jedis的下载地址:https://github.com/xetorthio/jedis
Jedis保存数据:jedis.set(“key”,”value”);
Jedis获取数据:jedis.get(“key”);
Jedis和jdbc类似,也可以使用连接池来获取数据;
比较常用是字符串String和哈希hash;
Redus是一个以key,value键值对的数据库;
Key的定义:不要太长,最好不要超过1024个字节,不仅会消耗内存,还会降低查询效率;不要太短;统一的命名规范;
存储字符串String,以二进制的形式来存储的;
存储字符串的常用命令:
set company imooc
表示:保存数据,将key的值imooc保存在company中;
get company
表示:取出数据,将company中的值取出来,得到的是imooc
del company
表示: 删除company中的值imooc,得到的是(integer)1
get company
表示:company中的值imooc已经删除了,此时已经拿不到imooc了,所以得到的是(nil)
incr num
表示:首先数据库redis中没有num,incr num会先将num的值赋值为0,然后加1;得到的结果是(integer)1;
incr num
表示:此时数据库redis中有了num,值为1,然后执行incr num表示经num的值加1,所以num的是为2;
get num
表示:获取num的值,值为2;
decr num2
表示:数据库redis中没有num2的值,数据库会先将num2的值赋值为0,然后再执行减1的操作,结果为(integer)-1;
incrby num 5
表示:将num的值加5,如果数据库redis中没有num,那么执行完incrby num 5结果是5;
decrby num 3
表示:将num的值减去3,结果为2;如果数据库redis中之前没有num,那么结果为-3;
append num 5
表示:在num的值后面追加字符5;如果num之前有值是3的话,那么get num的结果为”35”;那么 append num 5的结果为(integer)2,因为是字符串的长度;
Redis的数据结构的第二种:Hash存储
Redis中的hash可以看做是一种String的key和String的value的map容器;
非常适合存储值对象的信息, 比如存储用户名密码,姓名年龄等;如果hash中包含了很少的字段,那么这个类型的数据也将占有很少的磁盘空间;每一个hash可以存储很多个键值对;
hsetmyhash username jack
说明:hset命令进行设置,key是myhash,键值对是username jack;表示往里面去存值,结果为:(integer)1
hsetmyhash age 18
说明:hset命令进行设置,key是myhash,键值对是age 18;表示往里面去存值,结果为:(integer)1
hmsetmyhash2 username rose age 21
说明:hmset可以一起设置多个key和value;key是myhash2,键值对是:username rose和age 21;
hget取值
hgetmyhash username
说明:hget取值,取的key是myhash,要取的值是username中的内容;结果是jack
hmgetmyhash username age
说明:hmget获取多个属性的值;取的是username和age中的值,结果为:jack 18
hgetallhash
说明:hgetall表示获取key中所有的属性和属性的值;这里的结果是username jack age 18
hdel删除和del删除
hdelmyhash2 username age
说明:hdel表示删除myhash2中的username和age的属性,结果为(integer)2
hgetallmyhash2
说明:表示获取key为myhash2中的所有的属性和属性的值,结果为(empty list or set)表示是空的,获取不到
hdelmyhash2 username
说明:此时myhash2中已经没有值了,删除失败;所以结果是(integer)0
hsetmyhash2 username rose age 21
说明:往myhash2中存值;
delmyhash2
说明:删除myhash2中的属性和属性值,结果为:(integer)1
hgetmyhash2 username
说明:取属性为username中的值,结果为nil,表示没有取到,应为之前已经被删除了;
hgetmyhash age
说明:取出age属性中的值,结果为18;
hincrbymyhash age 5
说明:hincrby表示为某个属性增加数字;这里表示为age的属性值增加5;
hgetmyhash age
说明:取出age中的属性值,结果为23;
hexistsmyhash username
说明:hexists判断myhash中的username属性的值是否存在,存在就返回1,不存在就返回0;和结果是1;
hexistsmyhash password
说明:myhash中的password属性不存在,所以返回结果是0;
hlenmyhash
说明:表示获取myhash中的属性有几个,结果是(integer)2
hkeysmyhash
说明:获取所有的key,结果是username age
hvalsmyhash
说明:获取myhash中所有的值,结果是jack 23
Redis的数据结构的第三种:list存储
Redis中list的数据类型是按照插入顺序排序的一个字符串链表;和数据结构中的普通的链表是一样的;可以在头部(左侧)和尾部(右侧)去添加新的元素,在插入的时候,如果该键不存在,Redis就会为该键创造一个新的链表;如果链表中的所有元素搜被移除了,那么该键也会被数据库库删除;从元素插入和删除的视角来看呢,如果是在链表的两头插入和删除元素,这是非常高效的操作;如果链表中已经存在了百万条记录,从链表的两头插入和删除元素也是可以高效的完成;注意:如果元素的插入和删除是作用在链表的中间,那么这个时候的效率会比较低;
存储list方式
ArrayList使用数组的方式存储数据,很具索引去查询的速度是非常快的,但是新增和删除元素的时候需要涉及到位移操作,所以会比较慢;
LinkedList使用双向链接方式,每个元素都记录了前后元素的指针,插入和删除数据的时候只是改变了前后元素的指针所指向即可,速度都非常快;
双向链表中添加数据
双向链表中删除数据
lpush mylist a b c
说明:lpush表示从左侧向链表中添加数据,mylist表示key,
a b c表示往链表中放入数据,a是先进去的,在后面,b在中间,c最后进去的在最外边儿,在最左侧;结果为:(integer)3
lpush mylist 1 2 3
说明:从左侧向链表中插入数据;结果为:(integer)6
rpush mylist2 a b c
rpush mylist2 1 2 3
说明:rpush表示从右侧向链表中添加数据;结果为:(integer)6
lrange mylist 0 5
说明:lrange表示查看链表,mylist为想要查看的链表,后面的为从0开始到5结束;可以从0开始计数,也可以从负数开始计数,如果是-1表示是链表尾部的元素;-2则表示倒数第二个元素;命令的结果为:3 2 1 c b a
lrange mylist2 0 -1
说明:查看mylist2链表中的元素:从第0个到倒数第一个,结果是:a b c 1 2 3
lrange mylist2 0 -2
说明:查看mylist2链表中的元素:从第0个到倒数第二个,结果是:a b c 1 2
lpop mylist
说明:lpop表示从左边儿(头部)弹出,mylist为key,它会返回并弹出指定的key所关联的链表中的第一个元素,也就是它的头部元素;如果您不存在就会返回nil,如果存在就会返回第一个元素;mylist中的第一个元素是3,所以3就会被弹出来,结果为:3
lrange mylist 0 -1
说明:查看链表mylist中的元素,从第0个到倒数第一个;结果为:2 1 c b a
因为3已经被弹出了
rpop mylist2
说明:rpop表示从尾部(右边)弹出;也是3杯弹出了,结果为3
lrange mylist2 0 -1
说明:查看链表mylist2中的元素,从第0个到倒数第一个,结果为:a b c 1 2因为2已经被弹出了;
llen mylist
说明:llen表示获取链表中元素的个数;结果为5
llen mylist3
说明:因为链表mylist3是没有的链表,所以结果为(integer)0
lpushxmylist x
说明:lpushx表示仅当参数中指定的key存在的时候,可以向关联的链表的头部插入一个具体的值,如果key不存在就不会插入了;结果为:(integer)6
lrange mylist 0 -1
说明:查看链表mylist中的元素,从第0个到倒数第一个,结果为:x 2 1 c b a
lpushxmylist3 x
说明:mylist3这个key不存在,所以结果是(integer)0
rpushxmylist2 y
说明:key存在的时候,向关联的链表的尾部插入一个具体的值,key不存在就不插入了;这里的key存在,结果是(integer)6
lrangemylist2 0 -1
说明:查看链表mylist2中的元素,从第0个到倒数第一个,结果为:a b c 1 2 y
lremmylist
说明:lrem mylist后面跟上一个count value,该指令会删除count个为value的元素; 如果count大于0,从头向尾遍历并删除count个为value的元素;如果count小于0,从后面向前面去遍历;如果count等于0,删除链表中所有等于某个值的元素;
lpushmylist3 1 2 3
说明:往链表中插入1 2 3结果是(integer)3
lpushmylist3 1 2 3
说明:说明:往链表中插入1 2 3结果是(integer)6
lpushmylist3 1 2 3
说明:说明:往链表中插入1 2 3结果是(integer)9
lrange mylist3 0 -1
说明:查看mylist3链表里面的元素,结果为3 2 1 3 2 1 3 2 1
lrem mylist3 2 3
说明:lrem mylist3表示删除链表mylist3中的2个3的元素,2大于0,从头往尾删除2个为3的元素,结果为(integer)2
lrange mylist3 0 -1
说明:查看mylist3中的元素;结果为:2 1 2 1 3 2 1
lrem mylist3 -2 1
说明:-2小于0,从链表的尾部删除元素值为1 的元素,删除2个,结果为(integer)2
lrange mylist3 0 -1
说明:查看链表中的元素,结果为:2 1 2 3 2
lrem mylist3 0 2
说明:删除mylist3里面的所有的元素值为2的元素;结果为:(integer)3
lrange mylist3 0 -1
说明:查看链表中的所有的元素,结果为:1 3
lset
说明:lset设置链表中的某个index的脚标的元素的值;0代表第一个元素,-1代表最后那一个元素,不存在就抛出异常;
lrange mylist 0 -1
说明:查看mylist中的所有的元素,结果为:x 2 1 c b a
lset mylist 3 mmm
说明:往链表mylist中的下标(也叫脚标)为3的元素c的值设置为mmm,结果为OK
lrange mylist 0 -1
说明:查看链表mylist中的所有的元素的,结果为:x 2 1 mmm b a表示c被替代了;
lpush mylist4 a b c
说明:往mylist4中放入a b c元素,结果为:(integer)3
lpush mylist4 a b c
说明:往mylist4中放入a b c元素,结果为:(integer)6
lrange mylist4 0 -1
说明:查看mylist4中的所有的元素,结果为:c b a c b a
linsertmylist4beforeb 11
说明:表示往b元素之前插入11的值,结果为(integer)7
注意:之前用before,之后用after
lrange mylist4 0 -1
说明:查看mylist4中所有的元素,结果为:c 11 b a c b a
lrem mylist3 0 2
说明:删除mylist3中的所有的2
lrange mylist3 0 -1
说明:查看mylist3中的所有的元素,结果为1 3
lset
说明:lset设置链表中的某个index的脚标的元素的值,0代表第一个元素,-1代表最后一个元素,脚标不存在就会抛出异常;
lrange mylist 0 -1
说明:查看mylist链表中的所有的元素,结果为:x 2 1 c b a
lset mylist 3 mmm
说明:在mylist链表中设置第3个脚标的值为mmm,也就是将c改成mmm
lrange mylist 0 -1
说明:查看mylist中的所有的元素,结果为:x 2 1 mmm b a
lpush mylist5 1 2 3
说明:往mylist5链表中放入3个元素,结果为:(integer)3
lpush mylist6 a b c
说明:往mylist6链表中放入3个元素,结果为:(integer)3
lrange mylist6 0 -1
说明:查看mylist6中的所有的元素,结果为c b a
rpoplpush mylist5 mylist6
说明:rpoplpush表示从mylist5链表(3 2 1)中从右边开始弹出1个元素,然后从左边放入mylist6(c b a)中,结果为1
lrange mylist5 0 -1
说明:查看mylist5链表中的所有的元素;结果为:3 2
lrange mylist6 0 -1
说明:查看mylist6链表中的所有的元素;结果为:1 c b a
redis经常用于消息队列的消息服务,完成多个程序之间的消息交互;假设一个应用程序正在使用lpush向链表中添加新的元素,通常将这样的程序称为生产者,另一个程序正在使用rpop操作,从链表中取出元素,称为消费者;消费者程序在取出元素后崩溃,由于该消息已经被取出且没有被正常处理,我们认为这个消息已经丢失了,由此可能导致业务数据的丢失,或者导致业务状态的不一致等现象的发生,可以通过rpop,lpush这个命令,消费者程序在主消息队列中取出元素之后,再将它插入到一个备份的队列中,直到消费者程序完成正常的逻辑处理后,再讲消息从备份队列中删除,这样的话,我们可以提供一个守护的线程,当发现备份消息队列过期的时候,可以重新将它放到主消息的队列中,以便其他的消费者可以继续去处理;
Redis的数据结构的第四种:set存储
在redis中,可以将Set类型看做成没有排序的字符集合,和List类型一样;可以在该类型的数据值上执行添加,删除,判断某一个元素是否存在的操作;Set集合中不允许出现重复的元素,Set可包含的最大元素数量是4294967295;
sadd myset a b c
说明:往Set中添加元素a b c;结果为(integer)3
sadd myset a
说明:再往Set中添加元素a,这时是添加失败的,因为a元素已经存在了;
sadd myset 1 2 3
说明:往myset中添加元素 1 2 3,结果为(integer)3
srem myset 1 2
说明:删除myset中的1和2元素;结果为:(integer)2
smembers myset
说明:查看myset中的元素,结果为:c b a 3
sismember myset a
说明:查看元素a是否在myset中,如果存在就返回1,不存在就返回0;
sismember myset x
说明:查看元素x是否在myset中,结果是:(integer)0
集合的差集运算sdiff key1 key2
说明:集合的差集运算,返回集合中相差的成员,而且与key的顺序是有关系的;
saddmya1 a b c
说明:往mya1中添加3个元素a b c
saddmyb1 a c 1 2
说明:往myb1中添加4个元素a c 1 2
sdiffmya1 myb1
说明:求集合mya1和myb1的差集(与顺序有关),结果是:b
saddmya2 a b c
说明:往集合mya2中添加元素a b c
saddmyb2 a c 1 2
说明:往集合myb2中添加元素a c 1 2
sintermya2 myb2
说明:sinter为求两个集合中都有的部分,结果为a c
saddmya3 a b c
说明:往集合mya3中添加元素a b c
saddmyb3 a c 1 2
说明:往集合myb3中添加元素a c 1 2
sunionmya3 myb3
说明:sunion为求两个几个的并集;结果为:c 2 b a 1
smembersmyset
说明:查看myset中的元素;结果为:c b a 3
scardmyset
说明:查看myset中的元素的个数,结果为(integer)4
srandmembermyset
说明:srandmember随机的返回set中的一个成员;
sdiffstoremy1 mya1 myb1
说明:将两个集合相差的元素存储到一个新的集合,将mya1和myb1中相差的部分存储到新的集合my1中;结果为:(integer)1
smembers my1
说明:查看集合my1的元素,结果为b;
sinterstore
说明:求两个集合的交集,然后存储在一个新的集合中;
sinter mya2 myb2
说明:求两个集合的交集,结果为c a
sinterstore my2 mya2 myb2
说明:将集合mya2和myb2的交集存储在新的集合my2中;
smembers my2
说明:查看my2集合中的元素,结果为c a
sunion mya3 myb3
说明:查看集合mya3和myb3的并集的结果;
sunionstore my3 mya3 myb3
说明:将集合mya3和myb3的并集存储在一个新的集合my3中;
smembers my3
说明:查看my3中的所有的元素,结果为:c 2 b a 1
Set的具体使用场景:可以使用Redis的Set数据类型跟踪一些具有唯一性的数据;比如:访问某一博客的唯一ip地址的信息,在每次访问该博客的时候将访问者的ip存入到redis中,Set的数据类型就会自动保证ip地址的唯一性;还可以充分利用Set类型的服务器端聚合操作的方便高效的一些特性可以用于维护数据对象之间的一些关联关系;比如所有购买某一个电子设备的客户的id,被指定存储到一个指定的Set中,而购买另外一种电子设备的id被存储到了另外一个Set中,如果此时需要获取有哪些客户同时购买了这两种商品,这个时候使用这两个Set的交集就可以了;
Redis的数据结构的第五种:Sorted-Set存储
Sorted-Set不允许集合中出现重复的元素,Sort-Set中的每一个成员都会有一个分数与之关联;Redis就是通过这个分数来为集合中的成员进行从小到大的一个排序,尽管Sorted-Set中的成员必须是唯一的,但是分数却是可以重复的;Sorted-Set中添加,删除,更新一个成员都是非常快的操作;它的时间复杂度是集合中成员的个数的对数,由于Sorted-Set中的成员在集合中的位置是有序的的,即使是访问集合中间的成员也是非常高效的;
Sorted-Set的常用命令
zadd mysort 70 zs 80 ls 90 ww
说明:zadd为添加,mysort为key,每一个元素都有一个分数,70,80,90都为分数;zs,ls,ww分别为分数对应的元素;返回的是存到集合中的个数;结果为:(integer)3
zadd mysort 100 zs
说明:添加元素zs,如果已经存在了元素zs,那么会用新的分数100去替换原有的分数70;返回结果是:(integer)0因为之前有zs元素了,所以不显示;还是0;
zadd mysort 60 tom
说明:往mysort中新添加tom元素,结果为:(integer)1
zscore mysort zs
说明:zscort表示获取元素的的分数,结果为100
zcard mysort
说明:zcard获取mysort中的成员的数量,结果是(integer)4
zrem mysort tom ww
说明:zrem删除mysort中的tom和ww元素,结果为:(integer)2
zcard mysort
说明:zcard查看mysort中的元素的个数;结果为:(integer)2
zadd mysort 85 jack 95 rose
说明:往mysort中添加2个元素,jack和rose
zrange mysort 0 -1
说明:查看mysort中的所有的元素,结果为:ls jack rose zs
zrange mysort 0 -1 withscores
说明:查看mysort中所有的元素和分数;结果为:ls 80 jack 85 rose 95 zs 100;
zrevrange mysort 0 -1 withscores
说明:zrevrange从大到小查看mysort中的元素和分数;结果为:zs 100 rose 95 jack 85 ls 80
zremrangebyrank mysort 0 4
说明:按照范围进行删除,结果为(integer)4
zadd mysort 80 zs 90 ls 100 ws
zremrangebyscore mysort 80 100
说明:按照分数的范围进行删除,删除分数为80到100之间的元素;结果为:(integer)3
zrange mysort 0 -1
说明:查看mysort中的所有的元素,结果为:(empty list or set)
zadd mysort 70 zs 80 ls 90 ww
zrangebyscore mysort 0 100 withscores
说明:查看mysort中分数为0到100之间的元素,结果为:zs 70 ls 80 ww 90
zrangebyscore mysort 0 100 withscores limit 0 2
说明:查看mysort中的分数为0到100的元素中的2个元素和分数;结果为:zs 70 ls 80
zincrby mysort 3 ls
说明:设置指定成员ls增加的分数3;结果为:83
zscore mysort ls
说明:查看mysort中ls元素的分数,结果为83
zcount mysort 80 90
说明:查看分数在80到90之间的元素的个数,结果为(integer)2
Sorted-Set的使用场景:使用于大型网络游戏的积分排行榜;当玩家的分数发生变化的时候,可以使用zadd更新玩家的分数,然后通过zrange来获取积分;Sorted-Set可以用于构建索引数据;
Keys的通用操作
keys *
说明:查看所有的key
keys my?
说明:查看以my开头的所有key
del my1 my2 my3
说明:删除某个指定的key;删除my1和my2和my3的key;
exist my1
说明:查看某个key是否存在,如果存在就返回1,不存在就返回0;
get company
说明:获取key等于company的值;比如:结果为:baidu
rename company newcompany
说明:重命名key的名字,将key的名字改为newcompany
get company
说明:获取key等于company的值,此时的company已经不存在了,被改名字了,所以结果是(nil)
get newcompany
说明:获取key等于newcompany的值,结果是baidu
expire newcompany 1000
说明:设置key的过期时间,1000秒;
ttl newcompany
说明:查看key离超时还剩的时间;比如结果为:967;注意:如果没有设置key的超时时间,就会返回-1;
type newcompany
说明:查看key的类型;比如:结果为string
Redis的特性
Redis多数据库,Redis支持事务;
一个Redis的实例可以包含多个数据库;客户端可以指定连接某个Redis实例的哪个数据库;就好比是mysql中创建多个数据库一样,客户端连接的时候可以指定连接哪个数据库;一个Redis实例最多可以提供16个数据库;下标分别是熊0到15,客户端默认的连接是第0号数据库;也可以通过select来选择具体连接哪个数据库;
select 1
说明:连接1号数据库
keys *
说明:查看该数据库中的所有的key,结果是(empty list or set)
select 0
说明:连接0号数据库
keys *
说明:查看0号数据库的所有key,结果为:mylist2 myset mya1
move myset 1
说明:将myset这个key从0号数据库移到1号数据库;
select 1
说明:选择1号数据库
keys *
说明:查看1号数据库中的所有的key,结果为:myset;刚从0号数据库移过来的;
select 0
说明:选择0号数据库;
Redis中的实现事务的命令:multi和exec和discard;
在事务中,所有的命令将串行化,顺序执行;在事务执行的过程中,redis不会在为其他的数据库客户端提供任何的服务,从而保证事务中所有的命令都被原子化,和关系型数据库相比,在redis中,如果某一个命令执行失败了,后面的命令还是会被执行;
multi可以开启一个事务;后面的命令都将会被存到队列中,直到执行exec命令;
exec提交事务,
discard回滚
在事务开启之前,如果客户端和服务器之间出现通讯故障并导致网络断开;事务中的语句都将不会被服务器执行;如果网络中断发生在客户端执行之后的,那么事务中的所有命令都将会被服务器执行;
打开新的窗口
连接redis:cd /usr/local/redis
查看:ll
开启redi的客户端./bin/redis-cli
清空:clear
Redis的持久化
Redis所有的数据都存储在内存中;为了使redis在重启之后仍然能保证数据不丢失,那么就需要将数据从内存中同步到我们的硬盘上,这个过程我们称之为持久化;
Redis的持久化的方式;
RDB持久化:RDB的方式是默认支持的,不需要配置的,在指定的时间间隔内,将内存中的数据写到磁盘一次;可以指定30秒,50秒等等;
AOF持久化:以日志的形式记录服务器所处理的每一个操作,在redis服务器启动之初,AOF会读取该文件,重新构建数据库,这样保证启动后,数据是完整的;
无持久化:通过配置禁用redis的服务器的持久化的功能;这时的redis就是一个缓存的功能;
同时使用RDB和AOF的方式:
Redis持久化的RDB的方式;
RDB方式:一旦采用了RDB方式,整个Redis数据库将只包含一个文件,那么对于文件备份而言,是非常完美的;比如打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据,可以通过RDB方式的策略,一旦系统出现灾难性的故障,可以进行非常容易的进行恢复;对于灾难恢复而言,RDB是非常不错的选择,可以非常轻松的将一个单独的文件压缩后,再将它转移到其他的存储介质上,可以将它拷贝走,然后恢复的时候再把它拿出来;性能最大化,对于Redis的服务进程而言,在开始持久化的时候,它唯一需要做的是分叉出一些进程,然后由子进程完成持久化的工作,这样可以极大的避免服务器进程执行IO的操作;相比AOF的机制,如果数据集很大,RDB的启动效率会很高,整死RDB的优势,RDB的缺点:如果想要保证数据的高可用性,就是最大的限度避免数据的丢失,RDB将不是一个很好的选择,因为系统一定在定时持久化之前,出现一些宕机的情况,还没来得及往硬盘上面写,数据就丢失了;比如说30秒往硬盘上面写一次;当到了25秒的时候,服务器可能发生了宕机;还没来得及往硬盘上面去写内容的时候;那么前25秒的数据就没有了;RDB通过fork分叉的方式子进程来协助完成数据持久化工作的,因此当如果数据集非常大的时候,可能会导致服务器会停止几百毫秒甚至更长的时间;
RDB方式的配置:
cd /usr/local/redis
说明:比如进入到redis的路径下,
ll
说明:查看redis中的文件,比如有redis.conf文件;
vim redis.conf
说明:打开redis.conf的配置文件;
比如:save 900 1表示:每过900秒至少有1个key发生变化,和这个时候会持久化(持久化也就是往硬盘上写一次内容)1次;
Redis的AOF持久化的方式
AOF机制可以带来更高的数据安全性;
Redis提供了3种同步策略,每秒同步,每修改同步,不同步;
每秒同步:也是异步的,效率是非常高的;一旦系统出现宕机情况,这一秒钟修改的数据就会丢失;
每修改同步:可以视为同步持久化,每一次发生数据的变化,都会被立即的记录在磁盘中,这种效率是最低的;但是它是最安全的;
对于日志的操作采用的是append的模式,追加的模式;因此即使出现宕机的情况下,也不会破坏日志文件中已经存在的内容;然而如果本次操作只是写入了一半的操作,就出现了系统崩溃的问题;在Redis下一次启动之前,Redis-check-aof可以帮助解决数据一致性的问题;如果日志过大,Redis可以自动启动重写机制,Redis采用append的机制不断的将修改的数据写入到老的磁盘中,同时,redis还会创建一个新的文件用于记录此期间产生了哪些修改命令被执行了,因此在执行重写切换的时候;可以更好的保证数据的安全性;
AOF包含一个格式非常清晰的易于理解的日志文件用于记录所有的修改操作;
对于相同的数量的数据集而言,AOF文件比RDB的文件大一些,根据同步策略不同,AOF在运行的效率上比RDB低;
AOF的配置;
vim redis.conf
说明:打开redis.conf文件;
可以看到appendonly no
因为redis默认使用的是RDB的方式;
当然如果想要使用AOF的方式,可以将appendonly no改为appendonly yes的方式;这个时候会产生一个appendonly.aof的文件;
以下是3中同步策略:
appendsync always表示每修改一次都会同步到磁盘上,
appendsync everysec表示每秒钟往硬盘上写一次;
appendsync no表示不同步
wq表示保存文件;
./bin/redis-cli表示连接redis客户端;
./bin/redis-cli shutdown表示断开redis客户端;
shutdown表示断开;
./bin/redis-server ./redis.conf表示重新启动redis服务
clear表示清除屏幕
客户端操作实例:
set name jack
set num 10
set n1 12
说明:存入一些数据
keys *
说明:查看所有的key,结果为:n1 num name
flushall
说明:清空数据库里面的内容;
keys *
说明:查看数据库里面所有的key,结果为empty list or set,应为已经flushall了