from my typora
文章目录
redis 使用
redis基本命令
一个redis实例可以包括多个数据库,客户端可以指定连接某个redis实例的哪个数据库,就好比一个mysql中创建多个数据库,客户端连接时指定连接哪个数据库。
一个redis实例最多可以提供16个数据库,下标从0到15,客户端默认连接0号数据库,也可以通过select选择连接哪个数据库,如下连接1号库:
lsnu@lsnu-Aspire-AG1731:/usr/local/redis$ ./bin/redis-cli
127.0.0.1:6379> keys *
(empty list or set)
# select 同mysql中的use
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> select 15
OK
127.0.0.1:6379[15]> keys *
(empty list or set)
127.0.0.1:6379[15]> select 16
(error) ERR DB index is out of range
# 退出和mysql相同:exit或者quit
set [key]:设置一个键值对
$ set name mzy
get [key]:查看键值对:name
$ get name
del [key]:删除键值对:name
$ del name
keys *:查看当前数据库中的键值对(默认是0号库)
# 查看所有
$ keys *
clear:清屏
$ clear
select [0-15]:从默认的0号库改变到1号库
127.0.0.1:6379> select 1
OK
move [key] 0-15:将0号库中的name,移动到1号库中
# 定位到0号库
$ select 0
# 移动到一号库
$ move name 1
# 查看当前0号库中是否存在name
$ keys * / get name
(empty list or set) / (nil)
# 切换到1号库中,查看是否存在
$ select 1
$ keys * / get name
1) "name" / "mzy"
存放中文
127.0.0.1:6379> set name 哈哈哈
OK
127.0.0.1:6379> get name
"xe5x93x88xe5x93x88xe5x93x88"
echo:redis中也可以使用echo命令,但是我认为没什么用;
$ echo hhha
hhha
quit或exit:退出连接
quit / exit # 都可以
dbsize:返回当前数据库中key的数目
$ dbsize
127.0.0.1:6379> dbsize
(integer) 2
info:获取服务器的信息和统计
$ info
# Server
...
# Clients
...
# Memory
...
# Persistence
...
# Stats
...
# Replication
...
# CPU
...
# Cluster
...
# Keyspace
...
flushdb:删除当前选择数据库中的所有key:
$ flushdb
flushall:删除所有数据库的所有key:
$ flushall
redis做消息订阅与发布
redis所特有的,消息发布订阅:
开启三个redis客户端窗口:
在第一个连接中,订阅mychat频道。此时如果没有人“发布”消息,当前窗口处于等待状态。
127.0.0.1:6379> subscribe mychat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychat"
3) (integer) 1
在第二个窗口,向mychat窗口发布(publish)消息:
127.0.0.1:6379> publish mychat '111'
(integer) 1
发现第一个窗口马上显示出了’111’
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychat"
3) (integer) 1
1) "message"
2) "mychat"
3) "111"
在第三个窗口中使用psubcribe,订阅多个频道:
# 订阅所有以my* 开头的消息
127.0.0.1:6379> psubscribe my*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "my*"
3) (integer) 1
在第二个窗口中分别向mychat和mychat2发布消息:
127.0.0.1:6379> publish mychat '111'
(integer) 1
127.0.0.1:6379> publish mychat '222'
(integer) 2
127.0.0.1:6379> publish mychat '333'
(integer) 2
127.0.0.1:6379> publish mychat2 '333'
(integer) 1
127.0.0.1:6379>
发现窗口1:
127.0.0.1:6379> subscribe mychat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychat"
3) (integer) 1
1) "message"
2) "mychat"
3) "111"
1) "message"
2) "mychat"
3) "222"
1) "message"
2) "mychat"
3) "333"
发现窗口3:
127.0.0.1:6379> psubscribe my*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "my*"
3) (integer) 1
1) "pmessage"
2) "my*"
3) "mychat"
4) "222"
1) "pmessage"
2) "my*"
3) "mychat"
4) "333"
1) "pmessage"
2) "my*"
3) "mychat2"
4) "333"
只有窗口3收到了mychat2。
redis事务
和众多数据库一样,redis作为NoSQL数据库同样也提供了事务机制。
redis中的事务,通过MULTI/EXEC/DISCARD这三个命令实现事务。
1.在redis中,事务直接被设置为最高级别,所有命令都会被串行化的顺序执行,事务执行期间,redis不会再为其它任何客户端请求提供任何服务,从而保证了事务中的所有命令被原子的执行。
不要看redis是串行执行的,看起来好像很慢,其实不是,redis直接操作的内存,其实速度已经很快了;如果你设置它能为多个客户端同时提供服务,不通过串行的方式的话,我觉得反而是影响了redis的性能,因为这样来回切,进行隔离,反而降低了redis的执行速度!
同时补充:如果现在你要从D盘复制两个文件(文件A、文件B)到E盘中,你会同时复制还是一个个复制?
按照我们的惯性思维应该是同时复制,但是其实这样反而会更慢一些的,因为底层CPU要来回切换,一会儿复制一下文件A,一会儿复制一下文件B。切换反而更耗性能;由此说到了多线程编程,我认为大多数场景下多线程编程其实是不优的,除了一些特定的业务和逻辑场景,在我看来多线程编程大多数情况下很鸡肋。
2.和关系型的数据中的事务相比,在redis事务中如果有某一条命令执行失败,其后命令仍然会被继续执行。
而相比在我们的关系型数据库中,如果出现了事务异常,则会直接结束,不会往后执行了,并开始进行回滚。
3.redis事务的流程:通过MULTI命令开启事务(同关系型数据库中的begin transaction),该命令执行之后,执行所有命令都被视为事务之内的操作,最后通过执行EXEC(提交)/DISCARD(回滚)来批量处理该事务之内的所有操作!
multi:开启事务相当于关系型数据库中的begin transaction;
exec:相当于关系型数据库中的commit;
discard:相当于关系型数据库中的rollback;
4.在事务开启之前如果出现通讯故障网络中断,其后所有待执行的语句都不会被服务器执行。然而如果网络中断发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
5、当使用Append-0Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,I如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis 服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis- check-aof工具,该工具可以帮助我们定位到数据不一.致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。
测试事务
前:
incr,对一个数字进行增长,类似++:incr num 相当于 num++
incrby num 5,类似于num += 5:incr num 相当于 num = num + 5
测试redis连通性:
步骤1:在窗口1设置num,并获得数据
127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> get num
"1"
步骤2:在窗口2,num累加1,并获得数据
127.0.0.1:6379> get num
"1"
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> get num
"2"
步骤3:在窗口1,获得数据
127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> get num
"1"
127.0.0.1:6379> get num
"2"
# 发现已经受到影响
步骤4:在窗口1,开启事务,多次累加数据
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED # 在排队中...
127.0.0.1:6379> incr num
QUEUED
步骤5:在窗口2获得数据
# 发现此刻数据并没有变化
127.0.0.1:6379> get num
"2"
步骤6:在窗口1提交事务exec
127.0.0.1:6379> exec
1) (integer) 3
2) (integer) 4
步骤7:在窗口2查询num
# 发现事务已经提交了
127.0.0.1:6379> get num
"4"
步骤8:在窗口1再次累加(不开启事务)
127.0.0.1:6379> incr num
(integer) 5
127.0.0.1:6379> incr num
(integer) 6
步骤9:窗口2查询
# 受到影响
127.0.0.1:6379> get num
"6"
步骤10:窗口1开启事务累加两次,然后discard。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> discard
OK
步骤11:窗口2再次查询num
# 发现事务没有提交了
127.0.0.1:6379> get num
"6"
失败测试(测试和关系型数据库不一样的地方:在redis事务中如果有某一条命令执行失败,其后命令仍然会被继续执行。)
# 首先把num清0,避免造成误导
127.0.0.1:6379> set num 0
OK
# 开启事务
127.0.0.1:6379> multi
OK
# 增加5
127.0.0.1:6379> incrby num 5
QUEUED
# 不可识别的x,造成异常
127.0.0.1:6379> incrby num x
QUEUED
# 增加5
127.0.0.1:6379> incrby num 5
QUEUED
# 提交执行事务
127.0.0.1:6379> exec
1) (integer) 5
2) (error) ERR value is not an integer or out of range
3) (integer) 10
127.0.0.1:6379> get num
"10"
# 补:最后有人可能会想,如果我设置一个key为x,给一个数字的值,例如:5
# 那redis,会不会引用呢?答案是不会,至少在incrby 中不会,已测试!
补充:
以上:
multi必须和exec或者discard成对出现,不然会出现:(error) ERR MULTI calls can not be nested
redis的持久化
redis持久化支持两种方式:RDB和AOF;可以二者单独使用,也可以将二者结合使用。
RDB
快照:snapshots(比较节省空间,很快),记录当前在内存中的状态(只用记当前,不管过程)。
RDB的优势:
持久化只有一个文件,易于备份;并且因为是快照,只存数据的缘故,启动比AOF更快(数据量较大的情况下)。
在redis的根目录下,发现多了一个dump.rdb,就是redis持久化存储的数据(RDB方式下的)
lsnu@lsnu-Aspire-AG1731:/usr/local/redis$ ll
总用量 80
drwxr-xr-x 3 root root 4096 11月 10 16:29 ./
drwxr-xr-x 11 root root 4096 11月 9 18:02 ../
drwxr-xr-x 2 root root 4096 11月 9 18:06 bin/
-rw-r--r-- 1 root root 151 11月 10 16:29 dump.rdb
-rw-r--r-- 1 root root 62156 11月 9 18:23 redis.conf
所以归档就很容易了:直接备份dump.rdb这一个文件就好了!
RDB的劣势:
数据的高可用性无法保证,系统宕机的话,会造成数据丢失。
RDB采用fork子进程协助完成持久化,一旦数据量大了,可能造成服务器停止服务0-1000ms的情况。
RDB快照参数设置:
# 在redis.conf 中配置
save 900 1 # 每900秒,15分钟(如果有1个key发生变化),则dump内存快照。
save 300 10 # 每300秒,5分钟(如果有10个key发生变化),则dump内存快照。
save 60 10000 # 每60秒,1分钟(如果有10000个key发生变化),则dump内存快照。
AOF
以日志的方式记录,(记录了过程,做了什么,记下命令,记录修改、删除或者增加的操作;但是查询忽略了)
只要更改了redis,就记录下这些命令;原理就是,每次启动redis,把从最初开始执行过的所有:增、删、改命令全部执行一遍来恢复到当前状态。
AOF的劣势
1.相同数量的数据集,AOF文件通常大于RDB文件
2.同步的策略不同,导致AOF在运行上效率慢于RDB。
AOF的配置
always # 每次有数据修改都会写入AOF文件
everysec # 每秒钟同步一次,该策略为AOF的缺省策略
no # 从不同步。高效但是不会持久化。
# 默认是关闭的
appendonly no -> appendonly yes
# appendfsync always
appendfsync everysec
# appendfsync no
无持久化
就做缓存,不持久化。