Redis的学习笔记

1.1 Redis的介绍

Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串哈希表列表集合有序集合位图hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区

1.2 Redis的配置

步骤:

  1. 添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  2. 编写配置

    #Redis配置
    spring.redis.host=127.0.0.1
    spring.redis.port=6379
    
  3. 编写自定义配置

    @Configuration
    public class CommonConfig {
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
        @Bean
        public RedisTemplate<String,Object> redisTemplate(){
            //定义RedisTemplate实例
            RedisTemplate<String,Object> redisTemplate = new RedisTemplate<String,Object>();
            //设置Redis的链接工厂
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            //指定大Key序列化策略为String序列化,Value为JDK自带的序列化策略
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
            //指定Hashkey序列化策略为String序列化(针对Hash存储)
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            return redisTemplate;
        }
        @Bean
        public StringRedisTemplate stringRedisTemplate(){
            //采用默认配置即可
            StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
            stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
            return stringRedisTemplate;
        }
    }
    
  4. 测试

    1. 采用RedisTemplate将一字符串信息写入缓存中,并读取输出到控制台

      配置

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
      </dependency>
      <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.30</version>
          <scope>test</scope>
      </dependency>
      

      代码

      //单元测试
      @RunWith(SpringJUnit4ClassRunner.class)
      @SpringBootTest
      class RedisApplicationTests {
          //定义日志
          private static final Logger log = LoggerFactory.getLogger(RedisApplicationTests.class);
          @Autowired
          private RedisTemplate redisTemplate;
          @Test
          void contextLoads() {
              log.info("-----开始RedisTemplate操作组件实战-----");
              final String content = "RedisTemplate 实战字符串信息";
              final String key = "redis:template:string";
              //Redis通过的操作组件
              ValueOperations valueOperations = redisTemplate.opsForValue();
              log.info("写入缓存中的内容:{}",content);
              valueOperations.set(key,content);
              //从缓存中读取
              Object result = valueOperations.get(key);
              log.info("读取来的内容:{}",result);
          }
      }
      

      结果

      在这里插入图片描述

    2. 采用RedisTemplate将一对象信息序列化为JSON格式字符串后写入缓存中,然后将其读取出来,最后反序列化解析其中的内容并输出到控制台。

      class RedisApplicationTests {
          //定义日志
          private static final Logger log = LoggerFactory.getLogger(RedisApplicationTests.class);
          //定义RedisTemplate操作组件
          @Autowired
          private RedisTemplate redisTemplate;
          //定义JSON序列化与反序列化框架类
          @Autowired
          private ObjectMapper objectMapper;
          @Test
          void test() throws JsonProcessingException {
              log.info("-----开始RedisTemplate操作组件实战-----");
              //构造对象信息
              User user = new User(1,"debug","小A");
              //Redis通用的操作组件
              ValueOperations valueOperations = redisTemplate.opsForValue();
              //将序列化后的信息写入缓存中
              final String key = "redis:template:test:object";
              final String value = objectMapper.writeValueAsString(user);
              valueOperations.set(key,value);
              log.info("写入缓存对象的信息:{}",user);
              //从缓存中读取内容
              Object result = valueOperations.get(key);
              if(result!=null){
                  User resultUser = objectMapper.readValue(result.toString(),User.class);
                  log.info("读取缓存内容并反序列化后的结果:{}",resultUser);
              }
          }
       }
      

在这里插入图片描述

StringRedisTemplate和RedisTemplate的操作基本一样,只是将RedisTemplate操作组件改成StringRedisTemplate操作组件

1.3 Redis常见数据类型

1.3.1 字符串

​ 业务场景:将用户个人信息存储至缓存,实现每次前端请求获取用户个人详情信息时直接从缓存中读取。为了实现这个需求,首先需要建立用户对象实体,里面包含用户的个人信息,包括id、年龄、姓名、用户名以及住址等等,然后采用RedisTemplate操作组件将这一用户对象序列化为字符串信息并写入缓存,最后从缓存中读取即可。

class RedisApplicationTests {
    //定义日志
    private static final Logger log = LoggerFactory.getLogger(RedisApplicationTests.class);
    //定义RedisTemplate操作组件
    @Autowired
    private RedisTemplate redisTemplate;
    //定义JSON序列化与反序列化框架类
    @Autowired
    private ObjectMapper objectMapper;
    @Test
    void test() throws JsonProcessingException {
        log.info("-----开始RedisTemplate操作组件实战-----");
        //构造对象信息
        User user = new User(1,"debug","小A");
        //Redis通用的操作组件
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //将序列化后的信息写入缓存中
        final String key = "redis:template:test:object";
        final String value = objectMapper.writeValueAsString(user);
        valueOperations.set(key,value);
        log.info("写入缓存对象的信息:{}",user);
        //从缓存中读取内容
        Object result = valueOperations.get(key);
        if(result!=null){
            User resultUser = objectMapper.readValue(result.toString(),User.class);
            log.info("读取缓存内容并反序列化后的结果:{}",resultUser);
        }
    }
 }
1.3.2 列表

Redis列表的底层对于数据的存储和读取可以理解为一个“数据队列”,往列表中添加数据时,相当于往队列中的某个位置添加数据(如从队头添加数据);而从列表获取数据时,相当于从队列中的某个位置中获取数据(如从队尾获取数据)。

业务场景:将一组已经排好序的用户对象列表存储在缓存中,并按照排名的先后获取出来输出到控制台。对于这样的需求,首先需要定义一个已经排好序的用户对象列表,然后将其存储到Redis的列表中,最后按照排名先后按每个用户实体对象获取出来。

@Test
void listTest(){
    //构造一组用户姓名列表
    List<String> userList = new ArrayList<>();
    userList.add("debug");
    userList.add("jack");
    userList.add("修罗");
    userList.add("大圣");
    userList.add("jack");
    userList.add("修罗");
    userList.add("大圣");
    log.info("待处理的用户姓名列表:{}",userList);
    //将list的数据存入缓存,redis集合中的数据时不重复的。
    final String key = "redis:test:list";
    SetOperations setOperations = redisTemplate.opsForSet();
    for( String item:userList){
        setOperations.add(key,item);
    }
    //从缓存中获取用户对象集合
    Object result = setOperations.pop(key);
    while(result!=null){
        log.info("从缓存中获取的用户集合--当前用户:{}",result);
        result = setOperations.pop(key);
    }
}

在这里插入图片描述

1.3.3 有序集合

Redis的有序集合跟集合具有某些相同的特性,即存储的数据是不重复、无序和唯一的。而这两者的不同之处在于有序集合可以通过底层的Score(分数/权重)值对数据进行排序,实现存储的集合数据即不重复又有序,可以说其包含了列表、集合的特性。

业务场景:找出一个星期内手机话费单次充值金额前6的用户列表,要求按照充值金额从大到小的顺序进行排序,并存储至缓存中。

为了实现这一需求,首先需要构造一组对象列表,其中对象信息包括用户手机号、充值金额,然后需要遍历缓存的有序集合中,最终将其获取出来。

@Test
void zSetTest(){
    //构造一组无序的用户手机充值对象列表
    List<PhoneUser> list = new ArrayList<>();
    list.add(new PhoneUser("103",130.0));
    list.add(new PhoneUser("101",120.0));
    list.add(new PhoneUser("102",80.0));
    list.add(new PhoneUser("105",70.0));
    list.add(new PhoneUser("106",50.0));
    list.add(new PhoneUser("104",150.0));
    log.info("构造一组无序的用户手机充值对象列表:{}",list);
    final String key = "redis:test:zsettest";
    ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    for( PhoneUser u:list){
        //将元素添加进有序集合中
        zSetOperations.add(key,u,u.getFare());
    }
    //前端获取访问充值排名靠前的用户列表
    Long size = zSetOperations.size(key);
    //从大到小排序
    Set<PhoneUser> resSet = zSetOperations.reverseRange(key,0,size);
    for (PhoneUser u:resSet){
        log.info("从缓存中读取手机充值记录排序列表,当前列表:{}",u);
    }
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class PhoneUser implements Serializable {
    private String phone;
    private Double fare;
    //手机号重复,代表充值记录重复(只适用于特殊的排名需要),所以需要重写equals()和hashCode()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PhoneUser phoneUser = (PhoneUser) o;
        return phone!=null?Objects.equals(phone, phoneUser.phone):Objects.equals(phoneUser.phone,null);
    }
    @Override
    public int hashCode() {
        return phone!=null?phone.hashCode():0;
    }
}

在这里插入图片描述

要缓存的JavaBean必须实现Serializable接口,因为Spring会将对象先序列化再存入 Redis,或者使用JSON序列化JavaBean

1.3.4 Key失效与判断是否存在

在某些业务场景下,缓存中的Key对应的数据信息并不需要永久保留,这个时候我们就需要对缓存中的这些Key进行清理,在Redis缓存体系结构中,Delete与Expire操作都可以用于清理缓存中的Key,这两者不同之处在于Delete操作需要人为手动触发,而Exprie只需要提供一个TTL,即过期时间,就可以实现Key的自动失效,也就是过期的Key自动被清理,这有两种设置方法。

第一种方法:在调用set方法中指定Key的过期时间。

@Test
void testTTL1() throws Exception {
    final String key1 = "redis:testttl1";
    ValueOperations valueOperations = redisTemplate.opsForValue();
    valueOperations.set(key1,"exprie操作",10L, TimeUnit.SECONDS);
    Thread.sleep(5000);
    Boolean existKey = redisTemplate.hasKey(key1);
    Object value = valueOperations.get(key1);
    log.info("等待5秒-判断key是否还存在:{},对应的值:{}",existKey,value);
    Thread.sleep(5000);
    existKey = redisTemplate.hasKey(key1);
    value = valueOperations.get(key1);
    log.info("等待10秒-判断key是否还存在:{},对应的值:{}",existKey,value);
}

在这里插入图片描述

第两个方法:采用RedisTemplate操作组件的Exprie方法。

@Test
void testTTL12() throws Exception {
    final String key2 = "redis:testttl2";
    ValueOperations valueOperations = redisTemplate.opsForValue();
    valueOperations.set(key2,"exprie操作");
    redisTemplate.expire(key2,10L,TimeUnit.SECONDS);
    Thread.sleep(5000);
    Boolean existKey = redisTemplate.hasKey(key2);
    Object value = valueOperations.get(key2);
    log.info("等待5秒-判断key是否还存在:{},对应的值:{}",existKey,value);
    Thread.sleep(5000);
    existKey = redisTemplate.hasKey(key2);
    value = valueOperations.get(key2);
    log.info("等待10秒-判断key是否还存在:{},对应的值:{}",existKey,value);
}

在这里插入图片描述

1.4 Redis实战——缓存穿透

1.4.1 缓存穿透与解决方案

顾名思义,就是永远穿越了缓存而直接访问数据库。

将从数据库中获得的null结果直接存入缓存,那么下次就直接从缓存中获取null结果。

1.4.2 实战过程

步骤:

  1. 构建SQL表

  2. 使用Mybatis逆向工程生成xml、mapper和model

  3. 编写Controller

  4. 编写Service

    主要的业务在此,逻辑是先判断redis是否有对应key,若无则从数据库读取,并放入redis缓存中,**注意:无论数据库中有无数据都需要放入缓存中,否则会发生缓存穿透

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值