您的位置:首页 > 数据库 > Redis

Redis快速入门视频课程——笔记(二)

2018-08-05 12:49 381 查看
视频课程链接:http://edu.51cto.com/course/14463.html

四、Key操作命令

1. 命令列表

命令用法解释
keys pattern获取所有匹配pattern参数的Keys。需要说明的是,在我们的正常操作中应该尽量避免对该命令的调用,因为对于大型数据库而言,该命令是非常耗时的,对Redis服务器的性能打击也是比较大的。pattern支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。
del key [key...]从数据库删除中参数中指定的keys,如果指定键不存在,则直接忽略。
exists key判断指定键是否存在。
move key db将当前数据库中指定的键Key移动到参数中指定的数据库中。如果该Key在目标数据库中已经存在,或者在当前数据库中并不存在,该命令将不做任何操作并返回0。
rename key newkey为指定指定的键重新命名,如果参数中的两个Keys的命令相同,或者是源Key不存在,该命令都会返回相关的错误信息。如果newKey已经存在,则直接覆盖。
renamenx key newkey如果新值不存在,则将参数中的原值修改为新值。其它条件和RENAME一致。
persist key如果Key存在过期时间,该命令会将其过期时间消除,使该Key不再有超时,而是可以持久化存储。
expire key seconds该命令为参数中指定的Key设定超时的秒数,在超过该时间后,Key被自动的删除。如果该Key在超时之前被修改,与该键关联的超时将被移除。
expireat key timestamp该命令的逻辑功能和EXPIRE完全相同,唯一的差别是该命令指定的超时时间是绝对时间,而不是相对时间。该时间参数是Unix timestamp格式的,即从1970年1月1日开始所流经的秒数。
ttl key获取该键所剩的超时描述。
randomkey从当前打开的数据库中随机的返回一个Key。
type key获取与参数中指定键关联值的类型,该命令将以字符串的格式返回。

2. 操作

keys/del/exists/move/rename/renamenx

127.0.0.1:6379> flushdb
OK
#添加String类型的数据
127.0.0.1:6379> set mykey 2
OK
#添加List类型的数据
127.0.0.1:6379> lpush mylist a b c
(integer) 3
#添加Set类型的数据
127.0.0.1:6379> sadd myset 1 2 3
(integer) 3
#添加Sorted-Set类型的数据
127.0.0.1:6379> zadd myzset 1 "one" 2 "two"
(integer) 2
#添加Hash类型的数据
127.0.0.1:6379> hset myhash username "tom"
(integer) 1
#根据参数中的模式,获取当前数据库中符合该模式的所有key,从输出可以看出,该命令在执行时并不区分与Key关联的Value类型
127.0.0.1:6379> keys my*
1) "myset"
2) "mykey"
3) "myzset"
4) "myhash"
5) "mylist"
#删除了两个Keys
127.0.0.1:6379> del mykey mylist
(integer) 2
#查看刚刚删除的Key是否还存在,从返回结果看,mykey确实已经删除了
127.0.0.1:6379> exists mykey
(integer) 0
#查看一下没有删除的Key,以和上面的命令结果进行比较
127.0.0.1:6379> exists myset
(integer) 1
#将当前数据库中的myset键移入到ID为1的数据库中
127.0.0.1:6379> move myset 1
(integer) 1
#切换到ID为1的数据库
127.0.0.1:6379> select 1
OK
#查看当前数据库中的所有key
127.0.0.1:6379[1]> keys *
1) "myset"

#在重新打开ID为0的缺省数据库
127.0.0.1:6379[1]> select 0
OK
#清空数据库
127.0.0.1:6379> flushdb
OK
#准备新的测试数据
127.0.0.1:6379> set mykey "hello"
OK
#将mykey改名为mykey1
127.0.0.1:6379> rename mykey mykey1
OK
#由于mykey已经被重新命名,再次获取将返回nil
127.0.0.1:6379> get mykey
(nil)
#通过新的键名获取
127.0.0.1:6379> get mykey1
"hello"
#为renamenx准备测试key
127.0.0.1:6379> set oldkey "hello"
OK
127.0.0.1:6379> set newkey "world"
OK
#当新名称不存在时才会执行。由于newkey已经存在,因此该命令未能成功执行
127.0.0.1:6379> renamenx oldkey newkey
(integer) 0
#查看newkey的值,发现它并没有被renamenx覆盖
127.0.0.1:6379> get newkey
"world"


ttl/persist/expire/expireat

127.0.0.1:6379> flushdb
OK
#准备测试数据,将该键的超时设置为100秒
127.0.0.1:6379> set mykey "hello" ex 100
OK
#通过ttl命令查看还剩多少秒
127.0.0.1:6379> ttl mykey
(integer) 97
#立刻执行persist命令,该存在超时的键变成持久化的键,即将该Key的超时去掉
127.0.0.1:6379> persist mykey
(integer) 1
#ttl的返回值告诉我们,该键已经没有超时了
127.0.0.1:6379> ttl mykey
(integer) -1
#为后面的expire命令准备数据
127.0.0.1:6379> del mykey
(integer) 1
127.0.0.1:6379> set mykey "hello"
OK
#设置该键的超时被100秒
127.0.0.1:6379> expire mykey 100
(integer) 1
#用ttl命令看当前还剩下多少秒,从结果中可以看出还剩下96秒
127.0.0.1:6379> ttl mykey
(integer) 96
#重新更新该键的超时时间为20秒,从返回值可以看出该命令执行成功
127.0.0.1:6379> expire mykey 20
(integer) 1
#再用ttl确认一下,从结果中可以看出被更新了
127.0.0.1:6379> ttl mykey
(integer) 17
#立刻更新该键的值,以使其超时无效。
127.0.0.1:6379> set mykey "world"
OK
#从ttl的结果可以看出,在上一条修改该键的命令执行后,该键的超时也无效了
127.0.0.1:6379> ttl mykey
(integer) -1


type/randomkey

127.0.0.1:6379> del mykey
(integer) 1
#添加不同类型的测试数据
127.0.0.1:6379> set mykey 2
OK
127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> sadd myset 1 2 3
(integer) 3
127.0.0.1:6379> zadd myzset 1 "one" 2 "two"
(integer) 2
127.0.0.1:6379> hset myhash username "tom"
(integer) 1
#分别查看数据的类型
127.0.0.1:6379> type mykey
string
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type myset
set
127.0.0.1:6379> type myzset
zset
127.0.0.1:6379> type myhash
hash

#返回数据库中的任意键
127.0.0.1:6379> randomkey
"oldkey"
#清空当前打开的数据库
127.0.0.1:6379> flushdb
OK
#由于没有数据了,因此返回nil
127.0.0.1:6379> randomkey
(nil)


五、事务

1. 概述

​ 和其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。Redis中事务的特征:
​ 1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
​ 2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
​ 3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
​ 4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
​ 5). 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。

2. 命令列表

命令解释
multi用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。
exec执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。
discard回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将UNWATCH所有的Keys。

3. 操作

1. 事务被正常执行
#在当前连接上启动一个新的事务
127.0.0.1:6379> multi
OK
#执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列
127.0.0.1:6379> incr t1
QUEUED
#又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列
127.0.0.1:6379> incr t2
QUEUED
#执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
#只有当提交事务后,在其他连接中才能看到变化

2. 事务中存在失败的命令
#开启一个新的事务
127.0.0.1:6379> multi
OK
#设置键a的值为string类型的3
127.0.0.1:6379> set a 3
QUEUED
#从键a所关联的值的头部弹出元素,由于该值是字符串类型,而lpop命令仅能用于List类型,因此在执行exec命令时,该命令将会失败
127.0.0.1:6379> lpop a
QUEUED
#再次设置键a的值为字符串4
127.0.0.1:6379> set a 4
QUEUED
#获取键a的值,以便确认该值是否被事务中的第二个set命令设置成功
127.0.0.1:6379> get a
QUEUED
#从结果中可以看出,事务中的第二条命令lpop执行失败,而其后的set和get命令均执行成功,这一点是Redis的事务与关系型数据库中的事务之间最为重要的差别
127.0.0.1:6379> exec
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
4) "4"

3. 回滚事务
#为键t2设置一个事务执行前的值
127.0.0.1:6379> set t2 tt
OK
#开启一个事务
127.0.0.1:6379> multi
OK
#在事务内为该键设置一个新值
127.0.0.1:6379> set t2 ttnew
QUEUED
#放弃事务
127.0.0.1:6379> discard
OK
#查看键t2的值,从结果中可以看出该键的值仍为事务开始之前的值
127.0.0.1:6379> get t2
"tt"

六、主从复制Replication

1. 概述

​ 在Redis中配置Master-Slave模式非常简单,Redis中主从复制的特点和优势:
​ 1). 同一个Master可以同步多个Slaves。
​ 2). Slave同样可以接受其它Slaves的连接和同步请求,可以有效的分载Master的同步压力,所以可以将Redis的Replication架构视为图结构。
​ 3). Master Server是以非阻塞的方式为Slaves提供服务,所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
​ 4). Slave Server同样是以非阻塞的方式完成数据同步,在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
​ 5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
​ 6). Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。

2. 配置

​ 步骤:

同时启动两个Redis服务器,可以考虑在同一台机器上启动两个Redis服务器,分别监听不同的端口,如6379和6380

将配置文件拷贝两份,并修改端口号

启动服务器:

$ redis-server 6379.conf     #master主服务器
$ redis-server 6380.conf #slave从服务器


连接slave服务器,并执行如下命令:

$ redis-cli -p 6380   #连接从服务器,slave端口号为6380
127.0.0.1:6380> slaveof 127.0.0.1 6379 #配置主从关系,指定master的主机地址和端口号
OK

上面的方式只是保证了在执行slaveof命令之后,redis_6380成为了redis_6379的slave,一旦服务(redis_6380)重新启动之后,他们之间的复制关系将终止。

如果希望长期保证这两个服务器之间的Replication关系,可以在redis_6380的配置文件中做如下修改:

$ vi 6380.conf
slaveof 127.0.0.1 6379

这样就可以保证Redis_6380服务程序在每次启动后都会主动建立与Redis_6379的Replication连接了。

七、持久化

1. 概述

​ Redis提供的持久化方式:

RDB

该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。

AOF

该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

2. RDB

​ Redis Database:通过单文件的方式来持久化

​ RDB是默认的持久化方式,默认存储在启动redis服务器时所在当前目录下的dump.rdb文件中,一般都会修改存储在一个固定的目录中

​ 编辑配置文件:

$ vi myredis.conf
dbfilename dump.rdb                 #持久化文件的名称
#dir  ./                            #持久化文件的目录,默认为执行redis-server命令时所在的当前目录
dir /home/soft01/software/dump/     #修改存储位置为一个固定的目录

​ 持久化的时机:

在数据库关闭时会持久化(需要注意的是在数据库宕机时不会生成,数据可能会丢失)

满足特定条件时会持久化,编辑配置文件:

$ vi myredis.conf
save 900 1      #在900秒内,只要有1个key发生变化,就会dump持久化
save 300 10
save 60 10000


​ 优缺点:

缺点:可能会丢失数据

优点:效率比较高

3. AOF

​ Append Only File:通过操作日志的方式来持久化

​ 编辑配置文件:

$ vi myredis.conf
appendonly yes                      #开启aof模式的持久化
appendfilename "appendonly.aof"     #aof的持久化文件
appendfsync everysec                #每一秒进行一次持久化操作,可取值:always、everysec、no
dir /home/soft01/software/dump/     #持久化文件的目录,与RDB相同

​ 注:可以直接查看生成的appendonly.aof文件,可以认为是一个日志文件

​ 优缺点:

缺点:效率比较差

优点:丢失数据量比较少

八、Java访问Redis

1. 使用Jedis

​ Jedis是一个封装了redis的java客户端,集成了redis的一些命令操作,并提供了连接池管理功能

​ 步骤:

添加依赖

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>


基本用法

public void test01(){
//获取jedis的连接
Jedis jedis=new Jedis("192.168.19.37",6379);
//验证
jedis.auth("itany");

//操作redis
//jedis.set("name","tom");
//jedis.set("password","123","nx");
//System.out.println(jedis.get("name"));

//jedis.lpush("mylist","jack","alice","mike");
//System.out.println(jedis.lrange("mylist",0,1));

//jedis.sadd("myset","aaa","bbb","ccc");
//System.out.println(jedis.smembers("myset"));
//System.out.println();
//
//jedis.zadd("myzset",10,"a");
//jedis.zadd("myzset",20,"b");
//jedis.zadd("myzset",15,"c");
//System.out.println(jedis.zrange("myzset",0,-1));
//System.out.println();
//
//jedis.hset("user","name","alice");
//jedis.hset("user","age","21");
//Set<String> keys = jedis.hkeys("user");
//for (String key:keys){
//    System.out.println(key+"="+jedis.hget("user",key));
//}

Set<String> keys = jedis.keys("*");
System.out.println(keys);

//关闭连接
jedis.close();
}


2. 使用Spring Data Redis

​ 简称SDR,在Spring应用中读写Redis数据库更简单

​ 基于jedis
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息