【Redis】Redis入门详解(二)

【Redis】Redis入门详解(二)_第1张图片

(图片来源于网络,侵删)


一、Redis JavaAPI

我们使用maven构建项目,所以需要添加以下pom依赖,如果不需要打包,则可以省略 build中的内容

<dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <!--    <verbal>true</verbal>-->
                </configuration>
            </plugin>
        </plugins>
    </build>

【1】API使用案例1

public static void main(String[] args) {
        // 配置redis连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 设置连接池的最大连接数
        jedisPoolConfig.setMaxTotal(50);
        // 设置连接池最大空闲的数量
        jedisPoolConfig.setMaxIdle(10);
        // 设置连接池最小空闲的数量
        jedisPoolConfig.setMinIdle(5);
        // 连接最大超时时间
        jedisPoolConfig.setMaxWaitMillis(30000);
        // 创建redis连接池
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.100.111", 6379);
        // 获取redis对象
        Jedis jedis = jedisPool.getResource();

        // 预先删除
        jedis.flushDB();

        // 1、创建两个list  名字分别为ltest1    ltest2.
        // 2、Ltest1 从左到右为1 2 3 4 5 6 7 8 9,ltest2 从左到右为 f e d c b a
        jedis.lpush("ltest1", "9", "8", "7", "6", "5", "4", "3", "2", "1");
        jedis.lpush("ltest2", "a", "b", "c", "d", "e", "f");

        // 3、在Ltest1的3 左边插入3333
        jedis.linsert("ltest1", BinaryClient.LIST_POSITION.BEFORE, "3", "3333");

        // 4、在6右边插入6666
        jedis.linsert("ltest1", BinaryClient.LIST_POSITION.AFTER, "6", "6666");

        // 5、通过索引查询Ltest2 索引为3的数据
        String index_3 = jedis.lindex("ltest2", 3);
        System.out.println(index_3);

        // 6、将ltest2的e 修改为EEE
        jedis.lset("ltest2", 1, "EEE");

        // 7、只保留ltest2的EEE d c b
        jedis.ltrim("ltest2", 1, 4);

        // 8、移除ltest1右边一个数据并插入ltest2的左边
        jedis.rpoplpush("ltest1", "ltest2");

        System.out.println("ltest1 ---> " + jedis.lrange("ltest1", 0, -1));
        System.out.println("ltest2 ---> " + jedis.lrange("ltest2", 0, -1));

        // 将redis连接放回连接池
        jedis.close();
        // 关闭redis连接池
        jedisPool.close();
    }

【2】API使用案例2

public static void main(String[] args) {
        // 配置redis连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 设置连接池的最大连接数
        jedisPoolConfig.setMaxTotal(50);
        // 设置连接池最大空闲的数量
        jedisPoolConfig.setMaxIdle(10);
        // 设置连接池最小空闲的数量
        jedisPoolConfig.setMinIdle(5);
        // 连接最大超时时间
        jedisPoolConfig.setMaxWaitMillis(30000);
        // 创建redis连接池
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "192.168.100.111", 6379);

        // 获取redis对象
        Jedis jedis = jedisPool.getResource();
        // 清空数据
        jedis.flushDB();

        // 1.添加set 集合 setdemo1(aa,bb,cc,dd,ee,ff)    setdemo2(11,22,33,dd,ee,ff)
        jedis.sadd("setdemo1", "aa", "bb", "cc", "dd", "ee", "ff");
        jedis.sadd("setdemo2", "11", "22", "33", "dd", "ee", "ff");

        // 2.将两个集合的交集写入setdemo3
        jedis.sinterstore("setdemo3", "setdemo1", "setdemo2");

        // 3.将两个集合的并集写入setdemo4
        jedis.sunionstore("setdemo4", "setdemo1", "setdemo2");

        // 4.将setdemo2集合与setdemo1集合的差集写入setdemo5
        jedis.sdiffstore("setdemo5", "setdemo2", "setdemo1");

        // 5.将setdemo2内的11 移动到setdemo1内
        jedis.smove("setdemo2", "setdemo1", "11");

        // 6.删除setdemo1内的bb
        jedis.srem("setdemo1", "bb");

        System.out.println("setdemo1 ---> " + jedis.smembers("setdemo1"));
        System.out.println("setdemo2 ---> " + jedis.smembers("setdemo2"));
        System.out.println("setdemo3 ---> " + jedis.smembers("setdemo3"));
        System.out.println("setdemo4 ---> " + jedis.smembers("setdemo4"));
        System.out.println("setdemo5 ---> " + jedis.smembers("setdemo5"));

        // 将redis连接放回连接池
        jedis.close();
        // 关闭redis连接池
        jedisPool.close();
    }

二、Redis事务

【1】概述

  • Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
  • Redis事务的主要作用就是串联多个命令防止别的命令插队

【2】Multi、Exec、discard

  • 从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。
  • 组队的过程中可以通过discard来放弃组队
    【Redis】Redis入门详解(二)_第2张图片
  • 事务的错误处理
    组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消
    【Redis】Redis入门详解(二)_第3张图片
    如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他命令都会执行,不会回滚
    【Redis】Redis入门详解(二)_第4张图片

【3】悲观锁和乐观锁

  • 悲观锁(Pessimistis Lock):顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里就用到了很多这种机制,比如行锁,表锁,读锁,写锁,都是在做操作之前先上锁
  • 乐观锁(Optimistic Lock):顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新数据的时候会判断在此期间是否有别人更新这个数据,可以使用版本号等机制实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,Redis就是利用这种check-and-set机制实现事务的
    【Redis】Redis入门详解(二)_第5张图片

三、Redis持久化

【1】Redis 提供了2个不同形式的持久化方式

  • RDB (Redis DataBase)
  • AOF (Append Of File)

【2】RDB

1.RDB简介

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里

2.备份是如何执行的?

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失

3.关于fork

在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”,一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程

4.RDB的保存的文件

redis.conf中配置文件名称,默认为dump.rdb
【Redis】Redis入门详解(二)_第6张图片

5.RDB的保存策略

【Redis】Redis入门详解(二)_第7张图片

6.手动保存快照

SAVE或者BGSAVE命令手动触发RDB快照保存
SAVEBGSAVE两个命令都会调用 rdbSave函数,但它们调用的方式各有不同:

  • SAVE直接调用 rdbSave,阻塞 Redis 主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任何请求
  • BGSAVE则 fork 出一个子进程子进程负责调用 rdbSave,并在保存完成之后向主进程发送信号,通知保存已完成; Redis 服务器在BGSAVE 执行期间仍然可以继续处理客户端的请求
7.RDB相关参数配置

【Redis】Redis入门详解(二)_第8张图片
【Redis】Redis入门详解(二)_第9张图片
【Redis】Redis入门详解(二)_第10张图片

8.RDB备份

1.先通过 config get dir 查询 rdb 文件的目录
2.将dump.rdb的文件备份即可

9.RDB的恢复

1.关闭Redis
2.把备份的dump.rdb的文件拷贝到工作目录下
3.启动Redis, 备份数据会直接加载dump.rdb

10.RDB的优点和缺点

优点:

  • 1、对性能影响最小。Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率
  • 2、每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段
  • 3、使用RDB文件进行数据恢复比使用AOF要快很多

缺点:

  • 1、虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
  • 2、快照是定期生成的,所以如果Redis意外宕机的话,就会丢失最后一次快照后的所有修改
    【Redis】Redis入门详解(二)_第11张图片
11.RDB的触发条件
  • 1 在指定的时间间隔内,执行指定次数的写操作
  • 2 执行save(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令
  • 3 执行flushall 命令,清空数据库所有数据
  • 4 执行shutdown 命令,保证服务器正常关闭且不丢失任何数据

【3】AOF

1.AOF简介

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动时会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新

2.AOF配置

AOF默认不开启,需要手动在配置文件中配置
【Redis】Redis入门详解(二)_第12张图片

3.AOF和RDB同时开启,Redis听谁的?

如果AOF和RDB同时开启,那么Redis默认会使用AOF进行恢复数据,因为RDB触发保存机制是有条件的,如果没有达到触发条件,那么在这段没有触发条件的时间内,一旦宕机,那么数据就会丢失,而AOF默认是每秒都会保存写操作,相较于RDB,丢失数据的风险相较小一点,所以通过AOF恢复数据更保险
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020031420231049.png

4.AOF文件备份

AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是备份appendonly.aof即可,需要恢复时拷贝文件到Redis工作目录下,启动系统即加载

5.AOF文件修复

如遇到AOF文件损坏,可通过 redis-check-aof --fix appendonly.aof 进行恢复

6.AOF Rewrite

AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof

7.Redis AOF 如何实现重写?

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

8.Redis AOF 何时重写?

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写
在这里插入图片描述
系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,如果Redis的AOF当前大小 >= base_size + base_size*100% (默认) 且当前大小 >= 64mb(默认)的情况下,Redis会对AOF进行重写(rewrite)

9.AOF的优点和缺点
优点:
  • 1、最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据
  • 2、AOF文件损坏时,可以使用redis-check-aof工具轻松修复
  • 3、AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
缺点:
  • 1、AOF文件比RDB文件占用更多的磁盘空间
  • 2、数据恢复备份速度要慢
  • 3、性能消耗比RDB高
  • 4、存在个别Bug,造成不能恢复的严重问题

【Redis】Redis入门详解(二)_第13张图片

【4】RDB和AOF如何选择?

  • 官方推荐两个都启用
  • 如果对数据不敏感,可以选单独用RDB
  • 不建议单独用 AOF,因为可能会出现Bug
  • 如果只是做纯内存缓存,可以都不用

都看到这里了,点赞评论一下吧!!!

【Redis】Redis入门详解(二)_第14张图片

点击查看

【Redis】Redis入门详解(三)

你可能感兴趣的:(Redis)