Java学习篇59-Redis-常用指令与Jedis

如果对您有一丁点的帮助,劳烦动动手指点个赞,您的支持和鼓励是搬砖人不断创作的动力!

3. 常用指令

在这部分中呢,我们家学习两个知识,第一个是key的常用指令,第二个是数据库的常用指令。和前面我们学数据类型做一下区分,前面你学的那些指令呢,都是针对某一个数据类型操作的,现在学的都是对所有的操作的,来看一下,我们在学习Key的操作的时候,我们先想一下的操作我们应该学哪些东西:

3.1 key 操作分析

3.1.1 key应该设计哪些操作?

key是一个字符串,通过key获取redis中保存的数据

对于key自身状态的相关操作,例如:删除,判定存在,获取类型等

对于key有效性控制相关操作,例如:有效期设定,判定是否有效,有效状态的切换等

对于key快速查询操作,例如:按指定策略查询key

3.1.2 key 基本操作

删除指定key

del key

获取key是否存在

exists key

获取key的类型

type key

3.1.3 拓展操作

排序

sort

改名

rename key newkey
renamenx key newkey
3.1.3 key 扩展操作(时效性控制)

为指定key设置有效期

expire key seconds
pexpire key milliseconds
expireat key timestamp
pexpireat key milliseconds-timestamp

获取key的有效时间

ttl key
pttl key

切换key从时效性转换为永久性

persist key
3.1.4 key 扩展操作(查询模式)

查询key

keys pattern

查询模式规则

*匹配任意数量的任意符号 ? 配合一个任意符号 [] 匹配一个指定符号

keys *  keys    查询所有
it*  keys       查询所有以it开头
*heima          查询所有以heima结尾
keys ??heima    查询所有前面两个字符任意,后面以heima结尾 查询所有以
keys user:?     user:开头,最后一个字符任意
keys u[st]er:1  查询所有以u开头,以er:1结尾,中间包含一个字母,s或t

3.2 数据库指令

3.2.1 key 的重复问题

在这个地方我们来讲一下数据库的常用指令,在讲这个东西之前,我们先思考一个问题:

假如说你们十个人同时操作redis,会不会出现key名字命名冲突的问题。

一定会,为什么?因为你的key是由程序而定义的。你想写什么写什么,那在使用的过程中大家都在不停的加,早晚有一天他会冲突的。

redis在使用过程中,伴随着操作数据量的增加,会出现大量的数据以及对应的key。

那这个问题我们要不要解决?要!怎么解决呢?我们最好把数据进行一个分类,除了命名规范我们做统一以外,如果还能把它分开,这样是不是冲突的机率就会小一些了,这就是咱们下面要说的解决方案!

3.2.2 解决方案

redis为每个服务提供有16个数据库,编号从0到15

每个数据库之间的数据相互独立

在这里插入图片描述

在对应的数据库中划出一块区域,说他就是几,你就用几那块,同时,其他的这些都可以进行定义,一共是16个,这里边需要注意一点,他们这16个共用redis的内存。没有说谁大谁小,也就是说数字只是代表了一块儿区域,区域具体多大未知。这是数据库的一个分区的一个策略!

3.2.3 数据库的基本操作

切换数据库

select index

其他操作

ping
3.2.4 数据库扩展操作

数据移动

move key db

数据总量

dbsize

数据清除

flushdb  flushall

4. Jedis

在学习完redis后,我们现在就要用Java来连接redis了,也就是我们的这一章要学的Jedis了。在这个部分,我们主要讲解以下3个内容:

HelloWorld(Jedis版)

Jedis简易工具类开发

可视化客户端

4.1 Jedis简介

4.1.1 编程语言与redis

在这里插入图片描述

对于我们现在的数据来说,它是在我们的redis中,而最终我们是要做程序。那么程序就要和我们的redis进行连接。干什么事情呢?两件事:程序中有数据的时候,我们要把这些数据全部交给redis管理。同时,redis中的数据还能取出来,回到我们的应用程序中。那在这个过程中,在Java与redis之间打交道的这个东西就叫做Jedis.简单说,Jedis就是提供了Java与redis的连接服务的,里边有各种各样的API接口,你可以去调用它。

除了Jedis外,还有没有其他的这种连接服务呢?其实还有很多,了解一下:

Java语言连接redis服务 Jedis(SpringData、Redis 、 Lettuce)

其它语言:C 、C++ 、C# 、Erlang、Lua 、Objective-C 、Perl 、PHP 、Python 、Ruby 、Scala

4.1.2 准备工作

(1)jar包导入

下载地址:https://mvnrepository.com/artifact/redis.clients/jedis

基于maven

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

(2)客户端连接redis

连接redis

Jedis jedis = new Jedis("localhost", 6379);

操作redis

jedis.set("name", "itheima");  jedis.get("name");

关闭redis连接

jedis.close();

API文档

http://xetorthio.github.io/jedis/

4.1.3 代码实现

创建:com.itheima.JedisTest

public class JedisTest {

    public static void main(String[] args) {
        //1.获取连接对象
        Jedis jedis = new Jedis("192.168.40.130",6379);
        //2.执行操作
        jedis.set("age","39");
        String hello = jedis.get("hello");
        System.out.println(hello);
        jedis.lpush("list1","a","b","c","d");
        List<String> list1 = jedis.lrange("list1", 0, -1);
        for (String s:list1 ) {
            System.out.println(s);
        }
        jedis.sadd("set1","abc","abc","def","poi","cba");
        Long len = jedis.scard("set1");
        System.out.println(len);
        //3.关闭连接
        jedis.close();
    }
}

4.2 Jedis简易工具类开发

前面我们做的程序还是有点儿小问题,就是我们的Jedis对象的管理是我们自己创建的,真实企业开发中是不可能让你去new一个的,那接下来咱们就要做一个工具类,简单来说,就是做一个创建Jedis的这样的一个工具。

4.2.1 基于连接池获取连接

JedisPool:Jedis提供的连接池技术

poolConfig:连接池配置对象

host:redis服务地址

port:redis服务端口号

JedisPool的构造器如下:

public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) {
this(poolConfig, host, port, 2000, (String)null, 0, (String)null);
}
4.2.2 封装连接参数

创建jedis的配置文件:jedis.properties

jedis.host=192.168.40.130  
jedis.port=6379  
jedis.maxTotal=50  
jedis.maxIdle=10
4.2.3 加载配置信息

创建JedisUtils:com.itheima.util.JedisUtils,使用静态代码块初始化资源

public class JedisUtils {
    private static int maxTotal;
    private static int maxIdel;
    private static String host;
    private static int port;
    private static JedisPoolConfig jpc;
    private static JedisPool jp;

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("redis");
        maxTotal = Integer.parseInt(bundle.getString("redis.maxTotal"));
        maxIdel = Integer.parseInt(bundle.getString("redis.maxIdel"));
        host = bundle.getString("redis.host");
        port = Integer.parseInt(bundle.getString("redis.port"));
        //Jedis连接池配置
        jpc = new JedisPoolConfig();
        jpc.setMaxTotal(maxTotal);
        jpc.setMaxIdle(maxIdel);
        jp = new JedisPool(jpc,host,port);
    }

}
4.2.4 获取连接

对外访问接口,提供jedis连接对象,连接从连接池获取,在JedisUtils中添加一个获取jedis的方法:getJedis

public static Jedis getJedis(){
	Jedis jedis = jedisPool.getResource();
	return jedis;
}

4.3 可视化客户端

4.3.1 Redis Desktop Manager

在这里插入图片描述

5. 持久化

下面呢,进入到持久化的学习.这部分内容理解的东西多,操作的东西少。在这个部分,我们将讲解四个东西:

持久化简介

RDB

AOF

RDB与AOF区别

5.1 持久化简介

5.1.1 场景-意外断电

不知道大家有没有遇见过,就是正工作的时候停电了,如果你用的是笔记本电脑还好,你有电池,但如果你用的是台式机呢,那恐怕就比较灾难了,假如你现在正在写一个比较重要的文档,如果你要使用的是word,这种办公自动化软件的话,他一旦遇到停电,其实你不用担心,因为它会给你生成一些其他的文件。

在这里插入图片描述

其实他们都在做一件事儿,帮你自动恢复,有了这个文件,你前面的东西就不再丢了。那什么是自动恢复呢?你要先了解他的整个过程。

我们说自动恢复,其实基于的一个前提就是他提前把你的数据给存起来了。你平常操作的所有信息都是在内存中的,而我们真正的信息是保存在硬盘中的,内存中的信息断电以后就消失了,硬盘中的信息断电以后还可以保留下来!

在这里插入图片描述

我们将文件由内存中保存到硬盘中的这个过程,我们叫做数据保存,也就叫做持久化。但是把它保存下来不是你的目的,最终你还要把它再读取出来,它加载到内存中这个过程,我们叫做数据恢复,这就是我们所说的word为什么断电以后还能够给你保留文件,因为它执行了一个自动备份的过程,也就是通过自动的形式,把你的数据存储起来,那么有了这种形式以后,我们的数据就可以由内存到硬盘上实现保存。

5.1.2 什么是持久化

(1)什么是持久化

利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化 。

持久化用于防止数据的意外丢失,确保数据安全性。

(2)持久化过程保存什么?

我们知道一点,计算机中的数据全部都是二进制,如果现在我要你给我保存一组数据的话,你有什么样的方式呢,其实最简单的就是现在长什么样,我就记下来就行了,那么这种是记录纯粹的数据,也叫做快照存储,也就是它保存的是某一时刻的数据状态。

还有一种形式,它不记录你的数据,它记录你所有的操作过程,比如说大家用idea的时候,有没有遇到过写错了ctrl+z撤销,然后ctrl+y还能恢复,这个地方它也是在记录,但是记录的是你所有的操作过程,那我想问一下,操作过程,我都给你留下来了,你说数据还会丢吗?肯定不会丢,因为你所有的操作过程我都保存了。这种保存操作过程的存储,用专业术语来说可以说是日志,这是两种不同的保存数据的形式啊。

在这里插入图片描述

总结一下:

第一种:将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据。

第二种:将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程。

5.2 RDB

5.2.1 save指令

手动执行一次保存操作

save

save指令相关配置

设置本地数据库文件名,默认值为 dump.rdb,通常设置为dump-端口号.rdb

dbfilename filename

设置存储.rdb文件的路径,通常设置成存储空间较大的目录中,目录名称data

dir path

设置存储至本地数据库时是否压缩数据,默认yes,设置为no,节省 CPU 运行时间,但存储文件变大

rdbcompression yes|no

设置读写文件过程是否进行RDB格式校验,默认yes,设置为no,节约读写10%时间消耗,单存在数据损坏的风险

rdbchecksum yes|no

save指令工作原理

在这里插入图片描述

在这里插入图片描述

需要注意一个问题,来看一下,现在有四个客户端各自要执行一个指令,把这些指令发送到redis服务器后,他们执行有一个先后顺序问题,假定就是按照1234的顺序放过去的话,那会是什么样的?

记得redis是个单线程的工作模式,它会创建一个任务队列,所有的命令都会进到这个队列里边,在这儿排队执行,执行完一个消失一个,当所有的命令都执行完了,OK,结果达到了。

但是如果现在我们执行的时候save指令保存的数据量很大会是什么现象呢?

他会非常耗时,以至于影响到它在执行的时候,后面的指令都要等,所以说这种模式是不友好的,这是save指令对应的一个问题,当cpu执行的时候会阻塞redis服务器,直到他执行完毕,所以说我们不建议大家在线上环境用save指令。

5.2.2 bgsave指令

之前我们讲到了当save指令的数据量过大时,单线程执行方式造成效率过低,那应该如何处理?

此时我们可以使用:bgsave指令,bg其实是background的意思,后台执行的意思

手动启动后台保存操作,但不是立即执行

bgsave

bgsave指令相关配置

后台存储过程中如果出现错误现象,是否停止保存操作,默认yes

stop-writes-on-bgsave-error yes|no

其 他

dbfilename filename  
dir path  
rdbcompression yes|no  
rdbchecksum yes|no

bgsave指令工作原理

在这里插入图片描述

当执行bgsave的时候,客户端发出bgsave指令给到redis服务器。注意,这个时候服务器马上回一个结果告诉客户端后台已经开始了,与此同时它会创建一个子进程,使用Linux的fork函数创建一个子进程,让这个子进程去执行save相关的操作,此时我们可以想一下,我们主进程一直在处理指令,而子进程在执行后台的保存,它会不会干扰到主进程的执行吗?

答案是不会,所以说他才是主流方案。子进程开始执行之后,它就会创建啊RDB文件把它存起来,操作完以后他会把这个结果返回,也就是说bgsave的过程分成两个过程,第一个是服务端拿到指令直接告诉客户端开始执行了;另外一个过程是一个子进程在完成后台的保存操作,操作完以后回一个消息。

5.2.3 save配置自动执行

设置自动持久化的条件,满足限定时间范围内key的变化数量达到指定数量即进行持久化

save second changes

参数

second:监控时间范围

changes:监控key的变化量

范例:

save 900 1
save 300 10
save 60 10000

其他相关配置:

dbfilename filename
dir path
rdbcompression yes|no
rdbchecksum yes|no
stop-writes-on-bgsave-error yes|no

save配置工作原理

在这里插入图片描述

5.2.4 RDB三种启动方式对比
方式save指令bgsave指令
读写同步异步
阻塞客户端指令
额外内存消耗
启动新进程

RDB特殊启动形式

服务器运行过程中重启

debug reload

关闭服务器时指定保存数据

shutdown save

全量复制(在主从复制中详细讲解)

RDB优点:

  • RDB是一个紧凑压缩的二进制文件,存储效率较高
  • RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
  • RDB恢复数据的速度要比AOF快很多
  • 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。

RDB缺点

  • RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据
  • bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
  • Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象

5.3 AOF

为什么要有AOF,这得从RDB的存储的弊端说起:

  • 存储数据量较大,效率较低,基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
  • 大数据量下的IO性能较低
  • 基于fork创建子进程,内存产生额外消耗
  • 宕机带来的数据丢失风险

那解决的思路是什么呢?

  • 不写全数据,仅记录部分数据
  • 降低区分数据是否改变的难度,改记录数据为记录操作过程
  • 对所有操作均进行记录,排除丢失数据的风险
5.3.1 AOF概念

AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令 达到恢复数据的目的。与RDB相比可以简单理解为由记录数据改为记录数据产生的变化

AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

AOF写数据过程

在这里插入图片描述

启动AOF相关配置

开启AOF持久化功能,默认no,即不开启状态

appendonly yes|no

AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof

appendfilename filename

AOF持久化文件保存路径,与RDB持久化文件保持一致即可

dir

AOF写数据策略,默认为everysec

appendfsync always|everysec|no
5.3.2 AOF执行策略

AOF写数据三种策略(appendfsync)

  • always(每次):每次写入操作均同步到AOF文件中数据零误差,性能较低,不建议使用。

  • everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,在系统突然宕机的情况下丢失1秒内的数据 数据准确性较高,性能较高,建议使用,也是默认配置

  • no(系统控制):由操作系统控制每次同步到AOF文件的周期,整体过程不可控

5.3.3 AOF重写

场景:AOF写数据遇到的问题,如果连续执行如下指令该如何处理

在这里插入图片描述

什么叫AOF重写?

随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重 写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结 果转化成最终结果数据对应的指令进行记录。

AOF重写作用

  • 降低磁盘占用量,提高磁盘利用率
  • 提高持久化效率,降低持久化写时间,提高IO性能
  • 降低数据恢复用时,提高数据恢复效率

AOF重写规则

  • 进程内具有时效性的数据,并且数据已超时将不再写入文件

  • 非写入类的无效指令将被忽略,只保留最终数据的写入命令

    如del key1、 hdel key2、srem key3、set key4 111、set key4 222等

    如select指令虽然不更改数据,但是更改了数据的存储位置,此类命令同样需要记录

  • 对同一数据的多条写命令合并为一条命令

如lpushlist1 a、lpush list1 b、lpush list1 c可以转化为:lpush list1 a b c。

为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

AOF重写方式

  • 手动重写
bgrewriteaof

手动重写原理分析:

在这里插入图片描述

  • 自动重写
auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percentage

自动重写触发条件设置

auto-aof-rewrite-min-size size
auto-aof-rewrite-percentage percent

自动重写触发比对参数( 运行指令info Persistence获取具体信息 )

aof_current_size  
aof_base_size

自动重写触发条件公式:

在这里插入图片描述

5.3.4 AOF工作流程及重写流程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.4 RDB与AOF区别

5.4.1 RDB与AOF对比(优缺点)
持久化方式RDBAOF
占用存储空间小(数据级:压缩)大(指令级:重写)
存储速度
恢复速度
数据安全性会丢失数据依据策略决定
资源消耗高/重量级低/轻量级
启动优先级
5.4.2 RDB与AOF应用场景

RDB与AOF的选择之惑

  • 对数据非常敏感,建议使用默认的AOF持久化方案

AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出 现问题时,最多丢失0-1秒内的数据。

注意:由于AOF文件存储体积较大,且恢复速度较慢

  • 数据呈现阶段有效性,建议使用RDB持久化方案

数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段 点数据恢复通常采用RDB方案

注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结:

综合比对

  • RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
  • 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
  • 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
  • 灾难恢复选用RDB
  • 双保险策略,同时开启 RDB和 AOF,重启后,Redis优先使用 AOF 来恢复数据,降低丢失数据的量

欢迎扫描微信添加,技术交流+资源分享

ID: Txtechcom