redis

    1、什么是NOSQL?

             NoSQL ( Not only sql ) 是对不同于传统的关系数据库的数据库管理系统的统称,即广义地来说可以把所有不是关系型数据库的数据库统称为NotSQL。

    2、nosql和rdbms的区别

            NoSQL的特点:(Not Only SQL ) 非关系型数据库

              · 工具:Redis、Hbase、MongoDB

              · 应用:一般用于高并发高性能场景下的数据缓存或者数据存储

              · 特点:读写速度特别快,并发量非常高。相对而言,不如RDBMS稳定,对事务性的支持不太友好。

              · 开发:每种NoSQL都有自己命令语法

            RDBMS的特点:关系型数据库管理系统

              · 工具:MySQL、Oracle、SQL Server

              · 应用:业务性数据存储系统

              · 特点:体现数据之间的关系,支持事务,保证业务网完整性和稳定性,小数据量的性能也比较好。

    3、什么是redis

            Redis是一种开源的NoSQL内存数据库,用于高性能的数据存储和访问。Redis支持多种数据类型,包括字符串、哈希、列表、集合和有序集合,并且支持分布式存储和操作。Redis的特点包括快速、高可用和易扩展等,适用于各种引用场景。

    4、如何安装redis    

            (1)安装redis前,需要先安装c语言的插件  

               yum install gcc-c++    

            (2)下载redis软件

               https://redis.io/download/

            (3)把redis压缩包上传到linux指定目录下

                

            (4)解压redis

                tar -zxvf  redis-7.2.0.tar.gz

              (5) 进入解压目录 并编译源码

                make

            (6) 安装redis---帮你安装配置环境变量

                make install

            (7) 启动redis服务

                redis-server redis.conf

              (8) 客户端连接redis

                redis-cli -h【连接redis服务的ip】-p【连接redis的端口号】

   5、redis.conf配置

             (1)配置redis后台启动:

                

            (2)修改端口号

                     

            (3)查看进程端口号

                ps -ef | grep redis

                

            (4)关闭进程

                kill  -9 进程号

    6、安装redis图形化客户端软件

            等价于:mysql中的navicat. 可以通过图形化对redis进程操作。

            

            修改redis允许远程连接。

            (1)设置允许所有的ip连接该redis

                

            (2)设置是否开启保护模式-----yes开启 no表示关闭

              

            (3)默认redis提供了16个库。如果想修改库的个数

              

     7、redis中常用的命令

              (1)数据库的命令:

                  select 选择库。  ==默认为第一个库0~15

                  

                  flushall      ==清空所有库的内容

                  

                  flushdb      ==清空当前库的内容

                  

             (2)关于key的命令:

                  keys *:查看当前库中所有的key

                  

                  del key key ...:  删除指定的key

                  

                  exists key:  判断指定的key是否存在

                  

                  expire key seconds:  设置指定的key的过期时间 单位秒

                  

                  tll key:【ttl time to live】查看当前key的有效时间。-1表示永不过期

                  

     8、redis支持的数据类型

                     https://www.redis.net.cn/order/

                    redis中它的value类型为字符串类型,该类型最多可以存放512M的内容。

                    redis可以存放哪些数据库类型。---redis的value可以是哪些数据类型。

                  

 

             使用最多的类型为: Strings字符串类型,Lists队列类型,Sets集合类型,Hashes哈希类型,SortedSet 有序集合类型。

                

 

      9、字符串类型相关的命令

              

                 (1)set key value:    ==存储字符串类型的数据。这里的key不允许重复

                  

                  

                 (2) get key:        ==根据key获取对应的value值

                  

                 (3) mset key value key value .....:    ==存储多个key-value值

                  

                  

                (4) setnx key value:    ==如果指定的key存在,则不存入,如果不存在则存入

                 

                (5) incr key:        ==为指定的key递增。只能对整形。

                 

                (6) decr key:      ==为指定的key递减

                 

                (7)· decrby key number:    ==为指定的key递减相应的值

                 

     10、hash的数据类型命令

                  表示redis中它的value类型为hash数据类型。hash类型的特点: 它的value也是一个键值对的形式。

              (1) hset key field value:    ==存放hash类型的数据

                 

                 

              (2)hget key field:    --获取对应field字段的值

                  

              (3)hgetall key:      ==获取key对应hash数据内容

                  

              (4)hkeys key:        ==获取hash中所有field字段

                  

              (5)hvals key:        ==获取hash中所有的value值

                  

     11、List列表类型

                  它的value值为一个列表队列类型,列表中的元素允许重复。 key对应的value类型为一个列表类型。

              (1)lpush key value value ......:    ==从左边存放列表数据

                  

              (2)lpush key [count]:        ==从左边取出元素

                  

              (3)lrange key start end: ==从左边获取指定范围的元素 -1,表示最后一个元素

                  

     12、set集合命令

                  redis中的value类型为set集合类型,特点:无序不重复 的数据              

              (1)sadd key element element......:     ==存放set类型的元素。

                  

              (2)smembers key:      ==获取指定key对应的所有的元素

                  

               (3)srandmember key [ number ] :        ==随机获取集合中一个或者多个元素

                  

              (4) sinter key key :      ==求多个集合的交集

                  

              (5)spop key :        ==随机移除一个或者多个元素

                  

     13、sorted set 集合命令

                  它和set的区别就是在添加元素时需要指定一个分数,该分数用来排序的。

               (1) zadd key element score element score :    ==添加有序集合

                  

               (2)zrang key start end  [ withscores ]: ==从分数小到大的顺序获取集合中的元素

                  

              (3)zrevrange key start end  [ withscores ]:==返回有序集中指定区间内的成员,通过索引,分数从高到底

                  

     14、redis的应用场景

                · 热点数据的缓存:减少对数据库的访问频率,提供的用用程序的效率,

                ·限时业务的运用:比如短信验证码

                ·  计数器相关问题:点赞、关注数

                ·排行榜相关问题:销售量、观看量

                · 分布式锁自动锁手动锁

     15、redis 的持久化

            (1)为什么要持久化

                  Redis是内存数据库,宕机后数据会消失,Redis重启后快速恢复数据,要提供持久化机制。Redis的两种持久化方式:RDB和AOF

            (2)ROB持久化:每个一段时间对redis内存中的数据进行拍照存储 

                 优点:数据恢复速度快。

                 缺点:可能会出现丢失最后一段时间的数据 -- 数据完整性比较差。

                 RDB持久化方式的触发机制有两种方式:

                 第一种:手动触发

                  save 或 bgsave 命令:  ==持久化到磁盘中并且名字叫dump.rdb

                  save :

                    

                  该命令会阻塞当前Redis服务器,执行save命令期间,Redis 不能处理其他命令,直接RDB工程完成为止。执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。

              持久化到磁盘中并且名字叫dump.rdb :

                

              bgsave:

              执行该命令时,redis会在后台异步进行快照操作,快照同时会可以响应客户端请求。  

              

              第二种自动触发  --修改redis的配置文件【 底层是用的还是bgsave 】

              

           (3)AOF持久化

              AOF (Append Only File)持久化默认是关闭的,通过将redis.conf中将appendonly no,修改为appendonly yes来开启AOF持久化功能,如果服务器开始了AOF持久化功能,服务器会优先使用AOF文件来还原数据库状态。只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数库状态。

              优点:数据完整性好

              缺点:数据恢复慢

              默认redis没有开启aof模式。如果需要开启需要修改配置文件

              

    16、redis集群模式

            (1)主从模式

                

 

              搭建主从模式:原则配从不配主。

              需要准备三台redis服务。---两台从节点 一台为主节点。 我们为了操作方便我们就在一台虚拟机模拟主从集群模式。只需要让三台redis服务的端口号不同即可。

              第一台--主机:

              

              第二台--从机:

              

               连接主机:

              

              第三台--从机:

              

                连接主机:

              

              通过:info replication  查询主机

              

              

                通过:info replication  查询从机

              

         (2) 哨兵模式

              · 主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间类服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵)架构来决解这个问题。

              · 哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

            哨兵的作用:

               · 监控

                  不断的检查master和slave是否正常运行

                  master存活检测、master与slave运行情况检测

               · 通知

                  当被监控的服务器出现问题时,向其他( 哨兵间、客户端) 发送通知

               · 自动故障转移

                  断开master与slave连续,选取一个slave作为master,将其他slave链接到新的master,并告知客户端新的的服务器地址

               · 哨兵也是一台redis服务器,只是不提供数据服务器

               · 通常哨兵配置数量为单数

 

              

              

              

               启动哨兵:   redis-sentinel sentinel.conf

 

       (3)分片集群模式

              分片集群它是解决我们上面哨兵模式存在的问题。他们只有一个主节点,如果写操作频率过高,那么就会导致主节点宕机问题。

            分片集群结构图:

                          

              思考: 客户进行数据的写操作,那么它应该被写入到哪个主节点里面。

              解决办法: 使用了分槽技术。默认集群槽的数量为16384个。而每个槽可以存放若干个数据。如果搭建redis集群模式的化,为主节点平均分片这些槽。

              分槽的原理:

                  Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,每个分区里有很多key。

              搭建redis分片集群:

                准备6台redis服务: 3台主节点和3台从节点。[7001 7002 7003 7004 7005 7006]

              修改redis集群中6台配置文件的内容:

                1,修改端口号: 
                2. 修改rdb文件的名称
                3. 必须开启aof模式并修改aof文件的名称
                4. 开启redis集群模式 cluster-enabled yes
                5. 修改集群文件名 cluster-config-file nodes-7001.conf
                6. 设置允许任意ip访问。bind * -::* 

                

              根据配置文件启动6台redis服务

                

              为上面6台redis设置主从关系并分配槽:

                redis-cli --cluster create --cluster-replicas 1  ip:7001  ip:7002  ip:7003  ip:7004  ip:7005  ip:7006

              

             启动redis客户端          --  redis-cli -c -h 192.168.223.158 -p 7001

             测试数据:

                

     17、java连接redis     

                  jedis可以帮你完成java和redis之间的连接,专业易用的一个客户端。

         (1)引入jedis依赖

<dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.0</version>
        </dependency>
    </dependencies>

         (2)编写代码

public class Test01 {
    public static void main(String[] args) {
        //1.创建连接对象
        Jedis jedis=new Jedis("192.168.223.158",6379);
        //2.使用jedis来对我们的redis服务进行操作了。Jedis对象中对每个redis命令封装了对应的方法。
        //对key的操作命令
        Set<String> keys = jedis.keys("*");
        System.out.println("所有的key:"+keys);
        jedis.expire("k1",20L);
        Long k2 = jedis.del("k2");
        System.out.println("是否删除成功:"+k2);

        //关于字符串类型的操作。value为字符串。
        jedis.set("k4","k4就是香");

        jedis.setnx("k4","k4真的想骂");
        String va = jedis.get("k4");
        System.out.println("k4对应的值:"+va);

        jedis.setex("k5",20L,"设置一个过期的value");

        //关于hash类型的操作
        Map<String,String> map=new HashMap<String,String>();
        map.put("name","张三");
        map.put("age","25");
        map.put("address","北京");
        jedis.hset("k6",map);
        System.out.println(jedis.hget("k6", "name"));

        //关于list列表类型
        jedis.lpush("k7","张三","李四","王五","赵六");
        List<String> list = jedis.lrange("k7", 0, -1);
        System.out.println(list);

        //关于set和sortset省略
         jedis.close();
    }
}

       (3) java连接redis集群

public class Test02 {
    public static void main(String[] args) {
        Set<HostAndPort> set=new HashSet<HostAndPort>();
        set.add(new HostAndPort("192.168.223.158",7001));
        set.add(new HostAndPort("192.168.223.158",7002));
        set.add(new HostAndPort("192.168.223.158",7003));
        set.add(new HostAndPort("192.168.223.158",7004));
        set.add(new HostAndPort("192.168.223.158",7005));
        set.add(new HostAndPort("192.168.223.158",7006));
        //创建一个Jedis集群对象---需要传入redis集群服务的地址信息
        JedisCluster jedisCluster=new JedisCluster(set);
        jedisCluster.set("k66","v66");
        System.out.println(jedisCluster.get("k66"));

        jedisCluster.close();
    }
}

       (4)springboot整合redis

               springboot在整合redis时会自动封装了两个类:

                  RedisTemplate和StringRedisTemplate. StringRedisTemplate它是RedisTemplate的子类,

                  StringRedisTemplate它里面存储的key和value都是字符串类型。 

       (5)引入redis启动依赖jar包

               会完成自动装配功能。---完成RedisTemplate的创建以及容器管理。

<dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

        (6)修改application配置文件

                 # 连接单机redis
                  spring.redis.host=192.168.223.158
                  spring.redis.port=6379

        (7)使用StringRedisTemplate

             

@Autowired
    private StringRedisTemplate redisTemplate; //starter自动完成了redis的装配
    @Test
    void contextLoads() {
        //1. 操作key
//        System.out.println("=====================================关于key的操作==============================");
//        Boolean flag01 = redisTemplate.delete("k1");
//        System.out.println("是否删除指定key成功:"+flag01);
//        Boolean k2 = redisTemplate.hasKey("k2");
//        System.out.println("是否存在指定的key:"+k2);
//        Set<String> keys = redisTemplate.keys("*");
//        System.out.println("获取所有的key:"+keys);
//
//        //2. 关于字符串的操作:默认springboot中redistemplate不能直接操作数据类型的命令。但是springboot中redisTemplate为每个数据类型都提供了一个类
//        //对应的类可以操作对应的数据类型。
//        //ValueOperations:专门操作字符串类型
//        ValueOperations<String, String> forValue = redisTemplate.opsForValue();
//        forValue.set("k88","v88");
//        forValue.set("k99","v99",60, TimeUnit.SECONDS);
//
//        String k88 = forValue.get("k88");
//        System.out.println(k88);
//        Duration duration = Duration.ofDays(5);
//        forValue.setIfAbsent("k999","v999",duration);


        //3. 关于hash类型的操作
        HashOperations<String, Object, Object> forHash = redisTemplate.opsForHash();
        forHash.put("k1","name","张三");
        forHash.put("k1","age","18");

        Map<String,String> map=new HashMap<>();
        map.put("name","刘德华");
        map.put("age","19");
        map.put("address","香港");
        forHash.putAll("k2",map);

        Object o = forHash.get("k1", "name");
        System.out.println(o);

        Map<Object, Object> k2 = forHash.entries("k1");

        System.out.println(k2);
        //关于list  set  sortset的操作省略
    }

      (8)RedisTemplate

  @Autowired
    private RedisTemplate redisTemplate;

    //org.springframework.data.redis.serializer.SerializationException: 要求存入的key和value必须经过了序列化。
    //思考:存入字符串类型没有报错而存入User对象报错。【因为String序列化接口了,而User类没有实现序列化接口】
    //思考: 因为默认采用的是JDK序列化方式---无法看懂.---需要认为设置序列化方式
    @Test
    void contextLoads() {
        //指定了key的序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        //指定hash的key和value的序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
//        //字符串操作
//        ValueOperations valueOperations = redisTemplate.opsForValue();
//        User user=new User("张三",255);
//        valueOperations.set("userinfo",user);
//
//        System.out.println(valueOperations.get("userinfo"));

        //hash操作
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.put("k55","name","张三");

    }

        如果每次使用RedisTemplate都要序列化实在优点麻烦。 人为创建RedisTemplate类对象并交于spring容器管理。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashKeySerializer(redisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }
}

    18、 springboot连接redis集群

              # 集群redis
                spring.redis.cluster.nodes=192.168.223.158:7001,\
                              192.168.223.158:7002,\
                              192.168.223.158:7003,\
                              192.168.223.158:7004,\
                              192.168.223.158:7005,\
                              192.168.223.158:7006

 

posted @ 2023-08-29 10:50  PHOEDE  阅读(34)  评论(0)    收藏  举报