Redis 学习笔记

Redis相关问题

  • 对于Redis理解

Redis 简介icon-default.png?t=N7T8https://redis.com.cn/redis-intro.html

        一个开源的基于内存的非关系型数据库,也叫做键值对数据库。读写效率非常高,主要做缓存数据。将频繁访问的数据存入内存中,提高读写性能。

  • 优点:
  1. 高性能:Redis将数据存储在内存中,具有非常快速的读写速度。它采用高效的数据结构和算法,在处理大量请求时表现出色,适合于需要快速响应和处理大量并发请求的场景。
  2. 丰富的数据结构:Redis支持多种数据结构,如字符串、哈希、列表、集合和有序集合等。这些数据结构可以满足不同场景和需求的存储和操作要求,提供了更灵活的数据模型。
  3. 持久化:Redis支持将数据持久化到硬盘上,以便在服务器重启后进行恢复。它提供了两种持久化方式:快照(RDB)和日志(AOF)。
  4. 高可用性:Redis支持主从复制和哨兵机制,可以实现数据的自动备份和故障转移,提供了高可用性和数据冗余。
  5. 发布/订阅:Redis实现了发布/订阅模型,允许多个客户端通过订阅主题来接收消息。这在实时消息推送和事件驱动的应用程序中非常有用。
  6. 分布式缓存:Redis经常被用作分布式缓存系统,可以减轻后端数据库的负载,提高应用程序的性能和响应速度。
  • 缺点:
  1. 有限的存储容量:Redis的存储容量受限于服务器内存的大小,相比磁盘型数据库如MySQL,存储容量较小。因此,对于大规模数据的持久化和长期存储,Redis不如磁盘型数据库适合。
  2. 单线程限制:Redis采用单线程模型,虽然能够有效利用CPU和网络资源,但在处理大量并发写操作时可能会成为瓶颈。对于大规模并发写的场景,需要谨慎考虑Redis的性能瓶颈。
  3. 持久化配置复杂:Redis的持久化配置相对复杂,需要根据不同需求选择合适的持久化方式(RDB或AOF),并进行相应的设置和调优。
  4. 缺乏复杂查询支持:相对于关系型数据库如MySQL,Redis的查询功能较为有限。它主要支持简单的键值对存取和基本的数据结构操作,不适用于复杂的查询和数据关联。
  • Redis常用命令

官方手册 redis 命令手册icon-default.png?t=N7T8https://redis.com.cn/commands.html

  • Redis数据结构及使用场景

  1. 字符串:存储单个值的最基本数据结构,常用于缓存、计数器、分布式锁等场景
  2. 列表:有序可重复的字符串集合,支持在两端进行插入、删除等操作,通常用于实现队列、栈等数据结构。
  3. 集合:无序且唯一的字符串集合,支持并集、交集、差集等操作,适用于存储唯一值,并进行快速的集合运算。
  4. 有序集合:在集合的基础上为每个成员关联一个分数,使得集合中的成员可以按照分数进行排序,适用于排行榜、范围查询等场景。
  5. 哈希:存储字段和值的映射关系,适用于存储对象、用户信息等具有多个属性的数据。
  6. 地理信息:主要是Geo(Geospatial)数据结构,它是一种特殊的有序集合(Sorted Set),用于存储地理位置信息。
  • Redis相关面试题

  1. Redis的数据结构有哪些?
    Redis提供了五种基本数据结构:字符串、哈希、列表、集合和有序集合,以及其他数据类型如地理位置(Geo)和HyperLogLog等。
  2. Redis能否替代关系型数据库?
    虽然Redis提供了很多有用的功能,但它并不能完全替代关系型数据库。Redis最适合存储非关键数据,例如会话数据、缓存数据、计数器、排名列表等数据。对于复杂的事务支持,关系型数据库仍然是一个更好的选择。
  3. Redis中如何实现分布式锁?
    可以使用Redis的SETNX命令实现分布式锁。当多个客户端同时尝试获取锁时,只有一个客户端能成功获取并获得锁。获取锁后,客户端可以执行一段代码块,并在完成后释放锁。
  4. Redis如何处理数据持久化?
    Redis提供两种方式来进行数据持久化:RDB和AOF。RDB是将某一时刻的数据集快照存储到磁盘上,而AOF则是将每个命令追加到一个文件中。RDB适用于备份和恢复整个数据集,而AOF适用于更高级的数据可靠性。
  5. 如何通过Redis实现缓存?
    可以使用Redis作为缓存来提升应用程序的性能。将经常访问的数据存储在Redis中,可以减少对关系型数据库的访问次数,从而提高系统吞吐量。常见的缓存策略包括简单的键值对缓存、LRU缓存和时间到期缓存。

Redis代码实操

  • 添加依赖

<!-- 在 Spring Boot 项目中集成 Redis 的相关依赖项 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>${spring-boot.version}</version>
</dependency>



<!-- Hutool 工具库的小工具包,用来转化类型 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.15</version>
</dependency>
  • 配置文件

在application.properties配置文件设置

spring.redis.host=127.0.0.1
spring.redis.port=6379

小问题:可能会出现无法自动装配。找不到 'RedisConnectionFactory' 类型的 Bean。的警告

需要添加 @SuppressWarnings("all") 告知编译器忽略特定类型的警告信息

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.io.Serializable;

@Configuration
public class RedisConfiguration {

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Serializable> redisTemplate(
            RedisConnectionFactory redisConnectionFactory ) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // RedisTemplate 的键(key)和值(value)的序列化器
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setValueSerializer(RedisSerializer.json());
        // 哈希键(hash key)和哈希值(hash value)的序列化器
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        return redisTemplate;
    }
}
  • 缓存预热

在程序启动的时候将 SQL 的数据写入到 Redis 中

ApplicationRunner 是 Spring Boot 提供的一个接口,用于在应用程序启动后自动执行一些初始化操作。它定义了一个 run 方法,该方法在应用程序启动完成后被调用。

import com.example.adminarea.service.RoomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class RoomCatchPreload implements ApplicationRunner {
    @Autowired
    RoomService service;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        service.rebuildCatch();
    }
}
  • 计划任务

必须在主启动类上加上 @EnableScheduling 开启

Spring Boot 默认不开启计划任务

fixedRate:执行频率,以【上一次开始执行的时间】来计算下一次的执行时间,以毫秒为单位
fixedDelay:执行间隔,以【上一次执行结束的时间】来计算下一次的执行时间,以毫秒为单位
cron:使用cron表达式来配置,cron表达式的值是一个字符串,由6~7个域组成,各域之间使用空             格分隔

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class RoomCatchSchedule {
    // fixedRate执行频率,以上一次开始
    // fixedDelay执行间隔,以下一次开始
    // cron表达式 <秒> <分钟> <小时> <日期> <月份> <星期>
    @Scheduled(fixedDelay = 60 * 60 * 1000) // 1小时
    public void rebuildCache() {
        log.debug("计划任务执行!");
    }
}
  • 基本操作

  • 自动装配

@Autowired
RedisTemplate<String, Serializable> redisTemplate;
  • 字符串类型存取

// 存字符串数据
@Test
void setValue() {
    ValueOperations<String, Serializable> operations = redisTemplate.opsForValue();
    operations.set("username","专家1");
    System.out.println("存入成功!");
}
// 取字符串数据
@Test
void getValue() {
    ValueOperations<String,Serializable> operations = redisTemplate.opsForValue();
    Serializable value = operations.get("username");
    System.out.println("value = " + value);
}
  • 自定义对象存取

// 存入自定义对象
@Test
void setObjectValue() {
    Room room = new Room();
    room.setName("测试");
    room.setFloor(1);

    ValueOperations<String,Serializable> operations = redisTemplate.opsForValue();
    operations.set("Room",room);
    System.out.println("存入成功!");
}




// 取出自定义对象
@Test
void getObjectValue() {
    ValueOperations<String,Serializable> operations = redisTemplate.opsForValue();
    Serializable value = operations.get("Room");
    System.out.println("value = " + value);
}
  • 列表数据存取

// 存列表数据
@Test
void SetRoomList() {
    // 搞假数据进行测试
    List<Room> list = new ArrayList<>();
    for (int i=1;i<=8;i++) {
        Room room = new Room();
        room.setId(i+0L);
        room.setName("测试号");
        list.add(room);
    }

    ListOperations<String, Serializable> opsForList = redisTemplate.opsForList();

    // 将假数据存入
    String key = "RoomListSS";
    for (Room room : list) {
        opsForList.rightPush(key,room);
    }
    System.out.println("存入成功!");
}
 
 
// 读列表数据
@Test
void GetRoomList() {
    String key = "RoomListSS";
    ListOperations<String, Serializable> opsForList = redisTemplate.opsForList();

    // 得到长度
    Long size = opsForList.size(key);
    System.out.println("size = " + size);

    // 0 到 -1 表示全部
    long start = 0;
    long end = -1;
    List<Serializable> list = opsForList.range(key,start,end);
    for (Serializable serializable : list) {
        System.out.println(serializable);
    }
}
  • hash类型存取

// 存 hash 类型的数据
@Test
void hashPutAll() {
    String key = "test:room:hash2";

    Room room = new Room();
    room.setId(1L);
    room.setName("hash测试测试再次测试!!");

    /*HashMap<String, Object> map = new HashMap<>();
    map.put("id",room.getId());
    map.put("name",room.getName());*/
    Map<String, Object> map = BeanUtil.beanToMap(room); // 工具包作用直接转为 map 对象

    HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
    hash.putAll(key,map);
}
 
 
// 读取Redis中的hash数据
@Test
void hashEntries() {
    String key = "test:room:hash2";

    HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
    Map<Object, Object> entries = opsForHash.entries(key);
    System.out.println("entries = " + entries);

    // 小工具依赖包作用,将 map 转化为对象
    Room room = BeanUtil.mapToBean(entries, Room.class, true);
    System.out.println("room = " + room);
}




// 修改Redis中的hash数据
@Test
void hasPut() {
    String key = "test:room:hash2";
    HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
    hash.put(key,"name","修改");

    Map<Object, Object> entries = hash.entries(key);
    System.out.println("entries = " + entries);
}
  • 获取全部

// 获取全部
@Test
void keys() {
    String pattern = "*";
    Set<String> keys = redisTemplate.keys(pattern);
    System.out.println("keys = " + keys);
}
  • 删除单个

// 删除单个
@Test
void delete() {
    String key = "username";
    Boolean delete = redisTemplate.delete(key);
    System.out.println("delete结果 = " + delete);
}
  • 删除多个

// 删除多个
@Test
void deletes() {
    Set<String> keys = new HashSet<>();
    keys.add("username");
    keys.add("Room");

    Long delete = redisTemplate.delete(keys);
    System.out.println("成功delete几条 = " + delete);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值