Redis-认识与应用(从ChatGpt的角度看Redis)

 问题:您好,我的项目是在线教育平台,用springboot3搭建,我现在想学redis,请问redis能在我的项目中有什么应用场景呢

问题:就是我项目能应用上具体什么场景,请给我例子,并给我具体代码 

在你的在线教育平台项目中,Redis 可以用于多个具体场景。下面是几个常见的应用场景以及对应的代码示例:

1. 缓存课程列表
课程列表是一个频繁查询但不常变动的数据。可以使用 Redis 将课程列表缓存起来,减少对数据库的访问,提高查询性能。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class CourseService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CourseRepository courseRepository;

    private static final String COURSE_CACHE_KEY = "courses:list";

    // 获取课程列表
    public List<Course> getCourses() {
        // 先从 Redis 中获取缓存
        List<Course> courses = (List<Course>) redisTemplate.opsForValue().get(COURSE_CACHE_KEY);
        
        // 如果 Redis 中没有缓存,则从数据库中查询
        if (courses == null) {
            courses = courseRepository.findAll();
            // 查询后将结果缓存到 Redis,设置缓存时间为 10 分钟
            redisTemplate.opsForValue().set(COURSE_CACHE_KEY, courses, 10, TimeUnit.MINUTES);
        }
        
        return courses;
    }

    // 当课程列表发生变化时,清空缓存
    public void clearCourseCache() {
        redisTemplate.delete(COURSE_CACHE_KEY);
    }
}
2. 分布式会话管理
在你的项目中使用 Redis 存储用户的登录状态,确保多台服务实例下用户的会话保持一致性。

代码示例:
首先需要在 application.yml 中配置 Redis session 管理:

yaml
复制代码
spring:
  session:
    store-type: redis
  redis:
    host: localhost
    port: 6379
接着在 SpringBootApplication 类上添加注解:

java
复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@SpringBootApplication
@EnableRedisHttpSession // 启用 Redis Http Session
public class EduPlatformApplication {
    public static void main(String[] args) {
        SpringApplication.run(EduPlatformApplication.class, args);
    }
}
这样,用户的 session 信息(如登录状态)会自动存储到 Redis 中。

3. 限流防护
比如在用户登录时限制每个 IP 的登录请求次数,防止恶意攻击。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class LoginService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String LOGIN_ATTEMPT_KEY = "login:attempt:";

    public boolean login(String ip, String username, String password) {
        // 检查该 IP 是否已超过登录尝试次数
        String key = LOGIN_ATTEMPT_KEY + ip;
        Integer attempts = (Integer) redisTemplate.opsForValue().get(key);

        if (attempts != null && attempts >= 5) {
            throw new RuntimeException("登录尝试次数过多,请稍后再试");
        }

        // 假设验证通过
        boolean loginSuccess = validateLogin(username, password);

        if (loginSuccess) {
            // 登录成功,清除尝试计数
            redisTemplate.delete(key);
        } else {
            // 登录失败,增加尝试计数
            redisTemplate.opsForValue().increment(key, 1);
            // 设置键的过期时间为 1 小时
            redisTemplate.expire(key, 1, TimeUnit.HOURS);
        }

        return loginSuccess;
    }

    private boolean validateLogin(String username, String password) {
        // 实际的登录验证逻辑
        return "admin".equals(username) && "password".equals(password);
    }
}
4. 排行榜功能
例如,你可以用 Redis 的有序集合来存储课程热度,方便实现课程排行榜。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class RankingService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String COURSE_RANK_KEY = "courses:rank";

    // 增加课程热度
    public void incrementCourseRank(Long courseId) {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        zSetOperations.incrementScore(COURSE_RANK_KEY, courseId, 1); // 每次调用增加热度1
    }

    // 获取前 N 名热门课程
    public Set<Object> getTopCourses(int topN) {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.reverseRange(COURSE_RANK_KEY, 0, topN - 1); // 获取排名前N的课程
    }
}
5. 消息队列
你可以使用 Redis 的 List 实现简单的消息队列来处理异步任务,比如发送电子邮件通知。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class MessageQueueService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String EMAIL_QUEUE_KEY = "email:queue";

    // 将任务加入队列
    public void sendEmailTask(String emailContent) {
        redisTemplate.opsForList().leftPush(EMAIL_QUEUE_KEY, emailContent);
    }

    // 消费队列中的任务
    public String consumeEmailTask() {
        return (String) redisTemplate.opsForList().rightPop(EMAIL_QUEUE_KEY);
    }
}
以上这些例子展示了 Redis 在不同场景下的应用,你可以根据自己的需求将其整合到项目中。

问题:redis是时候频繁查询然后不变动的数据吗,就比如我有个发布课程,然后发布这里就不适合用redis,然后学生查看要学什么课程就可以应用,然后比如登录注册,注册就不适合用redis,登录后保存用户的信息就可以redis吗,是这样吗,给我具体例子

你的理解基本是对的,Redis 通常适用于频繁读取、少量写入的数据场景。我们可以根据不同的业务场景来分析是否适合使用 Redis。

不适合 Redis 的场景:数据会频繁更新或写入,比如课程发布和用户注册操作。这些操作需要确保数据的一致性和持久性,数据库更适合这种场景。

适合 Redis 的场景:数据不会频繁变化,或者是需要快速读取的数据,例如学生查看课程、登录后的用户信息缓存等。

具体场景和代码示例
1. 课程发布(不适合使用 Redis)
发布课程属于写操作,需要将数据存储在数据库中,以保证数据的持久性和一致性。所以发布课程的操作不适合用 Redis,直接保存到数据库即可。

代码示例:
java
复制代码
@Service
public class CourseService {

    @Autowired
    private CourseRepository courseRepository;

    public Course publishCourse(Course course) {
        // 直接保存课程到数据库
        return courseRepository.save(course);
    }
}
2. 学生查看课程(适合使用 Redis)
学生查看课程列表是频繁的读取操作,课程列表一般不会频繁变动,适合缓存到 Redis 中,减少数据库查询压力。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class CourseService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CourseRepository courseRepository;

    private static final String COURSE_CACHE_KEY = "courses:list";

    // 获取课程列表
    public List<Course> getCourses() {
        // 先从 Redis 中获取缓存
        List<Course> courses = (List<Course>) redisTemplate.opsForValue().get(COURSE_CACHE_KEY);
        
        // 如果 Redis 中没有缓存,则从数据库中查询
        if (courses == null) {
            courses = courseRepository.findAll();
            // 查询后将结果缓存到 Redis,设置缓存时间为 10 分钟
            redisTemplate.opsForValue().set(COURSE_CACHE_KEY, courses, 10, TimeUnit.MINUTES);
        }
        
        return courses;
    }

    // 当课程列表发生变化时,清空缓存
    public void clearCourseCache() {
        redisTemplate.delete(COURSE_CACHE_KEY);
    }
}
3. 用户注册(不适合使用 Redis)
用户注册属于写操作,数据需要持久化存储在数据库中,Redis 不适合这类场景。

代码示例:
java
复制代码
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    // 注册用户,直接保存到数据库
    public User registerUser(User user) {
        return userRepository.save(user);
    }
}
4. 用户登录后保存用户信息(适合使用 Redis)
登录后,用户信息是频繁读取的,但通常不会频繁修改。可以将登录后的用户信息存储在 Redis 中,以便后续快速访问。

代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class UserService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private UserRepository userRepository;

    private static final String USER_SESSION_KEY = "user:session:";

    // 登录用户
    public User login(String username, String password) {
        User user = userRepository.findByUsernameAndPassword(username, password);
        if (user != null) {
            // 将用户信息存储到 Redis,缓存时间为 30 分钟
            redisTemplate.opsForValue().set(USER_SESSION_KEY + user.getId(), user, 30, TimeUnit.MINUTES);
        }
        return user;
    }

    // 获取缓存中的用户信息
    public User getUserFromCache(Long userId) {
        return (User) redisTemplate.opsForValue().get(USER_SESSION_KEY + userId);
    }

    // 注销用户,删除 Redis 中的缓存
    public void logout(Long userId) {
        redisTemplate.delete(USER_SESSION_KEY + userId);
    }
}
场景总结:
课程发布:不适合使用 Redis,直接保存到数据库。
学生查看课程:适合使用 Redis 缓存,减少数据库访问,提高查询性能。
用户注册:不适合使用 Redis,直接保存到数据库。
用户登录后信息缓存:适合使用 Redis,缓存用户信息,加快后续的查询速度。
你可以根据这些代码示例,将 Redis 应用于合适的场景中,保证系统的性能和稳定性。

问题:那像您说的排行榜、点赞,这些不都一直在变化吗,为什么时候redis,是我理解错了吗

你的问题很有道理。确实,像排行榜、点赞等场景涉及到频繁更新数据,那为什么我们依然推荐 Redis 呢?

关键点在于这些场景通常不是对持久化强一致性的要求特别高,而是频繁的读操作和写操作的高性能要求。Redis 在处理频繁更新且数据较简单的场景下,具有高效的写入和读取性能。因此,虽然数据在不断变化,但 Redis 可以通过它的内存数据结构和异步持久化机制来应对这些频繁变化的情况。

为什么排行榜、点赞适合 Redis?
高并发写入能力:Redis 是内存数据库,写入速度快,特别适合应对高并发的场景。
读写分离:对于读操作频繁的场景,Redis 可以大幅减轻数据库的压力。
有序集合(Sorted Set):Redis 提供了非常适合排行榜的有序集合结构,能够按分数排序,更新分数时不需要全量重新排序,直接更新即可。
最终一致性:这些场景往往对实时一致性要求不高,更关注响应速度。在数据最终需要持久化到数据库时,可以定时同步。
具体场景和代码示例
1. 排行榜(课程热度排名)
比如你的在线教育平台可以通过课程的学习人数或浏览次数生成一个课程热度排行榜。

Redis 使用有序集合 (Sorted Set):每个课程都有一个热度分值,每当学生学习或浏览时,分值会增加,然后可以按照分值排序展示热门课程。
代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class RankingService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String COURSE_RANK_KEY = "courses:rank";

    // 增加课程热度
    public void incrementCourseRank(Long courseId) {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        // 为课程热度增加 1 分
        zSetOperations.incrementScore(COURSE_RANK_KEY, courseId, 1);
    }

    // 获取前 N 名热门课程
    public Set<Object> getTopCourses(int topN) {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        // 获取热度排名前 N 的课程
        return zSetOperations.reverseRange(COURSE_RANK_KEY, 0, topN - 1);
    }

    // 获取某一课程的排名和热度分数
    public Double getCourseScore(Long courseId) {
        ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
        return zSetOperations.score(COURSE_RANK_KEY, courseId);  // 获取课程热度分数
    }
}
2. 点赞功能
点赞属于频繁的加减操作,可以通过 Redis 的自增功能来快速实现,同时可以将点赞数据异步同步到数据库中进行持久化。

Redis 使用哈希 (Hash):每个课程的点赞数存储在 Redis 中,用户点赞或取消点赞时,直接对 Redis 中的数据进行操作。
代码示例:
java
复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class LikeService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String COURSE_LIKE_KEY = "courses:like";

    // 为课程点赞
    public void likeCourse(Long courseId) {
        // Redis 哈希结构,课程 ID 为字段,点赞数为值
        redisTemplate.opsForHash().increment(COURSE_LIKE_KEY, courseId, 1); // 点赞数 +1
    }

    // 取消点赞
    public void unlikeCourse(Long courseId) {
        redisTemplate.opsForHash().increment(COURSE_LIKE_KEY, courseId, -1); // 点赞数 -1
    }

    // 获取某课程的点赞数
    public Integer getCourseLikes(Long courseId) {
        return (Integer) redisTemplate.opsForHash().get(COURSE_LIKE_KEY, courseId);
    }
}
Redis 的适用场景总结:
虽然 Redis 适用于频繁变化的数据,但它非常适合频繁的读写操作且对实时一致性要求不高的场景。你可以把 Redis 用作缓存层,并定期将数据同步到持久化存储(如 MySQL),保证数据的持久性和一致性。
像排行榜、点赞等场景,不需要每次操作都立即写入数据库,而是可以将快速变化的数据保存在 Redis 中,并在需要时批量同步到数据库,提高系统的整体性能。
通过这种方式,Redis 可以同时满足高并发读写的需求,保证高性能的同时减少数据库的压力。

 

问题:那您的意思就是redis适合,查一般不怎么变化的数据,给他存起来可以直接从redis访问,然后就是不需要马上更新到数据库的数据,可以先存于redis,然后通过redis一定时间后存于mysql,您具体说一下redis适合什么时候,谢谢


是的,Redis 非常适合以下两类场景:

频繁读取、不常更新的数据:将这些数据存储在 Redis 中,避免频繁查询数据库,以提高响应速度。
高并发写入、不需要立即持久化的数据:Redis 可以先暂时存储数据,通过定时任务或者特定触发条件,再将数据批量写入数据库,减轻数据库压力。
Redis 适合的场景分类
1. 缓存数据,减少数据库压力
当数据频繁读取但不经常更新时,可以将其缓存到 Redis 中。典型场景包括:

课程列表、分类、配置文件等:这些数据经常被学生或教师查看,但更新较少,适合存放在 Redis 中。
用户个人信息:用户登录后频繁查看个人信息,但这些信息不会频繁更改。
通过缓存数据,可以大幅减少对数据库的查询压力,同时提升系统的响应时间。

适用场景:

频繁查询的静态数据(如课程分类、系统配置等)
用户个人信息缓存
商品信息、评论列表等
2. 分布式会话管理
在多台服务器或微服务架构中,用户登录后的会话状态需要在不同的服务节点之间共享。Redis 提供了快速、统一的分布式会话管理解决方案。

适用场景:

用户登录后的分布式会话共享
临时数据存储,如购物车、登录状态等
3. 排行榜和计数
Redis 的有序集合 (Sorted Set) 数据结构非常适合实现排行榜、点赞、计数等功能。由于 Redis 是内存数据库,读写性能高,可以快速响应用户的查询需求。

适用场景:

课程的热度排名
用户学习进度的排名
点赞计数、评论计数
4. 限流与防止重复提交
可以用 Redis 实现限流功能,例如限制用户在短时间内重复操作,防止恶意攻击或滥用接口。Redis 也可以用来避免重复提交表单或重复请求 API。

适用场景:

登录尝试限制
评论/发帖频率限制
防止重复订单提交
5. 消息队列
Redis 的 List 和 Pub/Sub 结构可以实现简单的消息队列,用于处理异步任务。比如,处理用户下单后发邮件通知、日志异步写入等耗时操作,可以通过 Redis 消息队列异步执行,减轻主业务线程压力。

适用场景:

异步任务处理,如邮件发送、数据处理等
消息通知系统
6. 延迟队列和任务调度
Redis 的 List 数据结构可以用于实现延迟队列,调度一些延时执行的任务。例如:在电子商务中,订单未支付超过30分钟后取消,可以通过 Redis 来管理这样的延迟任务。

适用场景:

延迟执行任务,如自动取消订单、定时通知等
异步任务调度
7. 分布式锁
在分布式系统中,需要保证某些操作的原子性,可以使用 Redis 实现分布式锁。它可以确保多个服务实例不会同时操作同一份资源,防止数据竞争或资源冲突。

适用场景:

分布式系统中的互斥操作(如库存扣减、订单生成)
防止并发修改数据
8. 实时数据和统计
Redis 非常适合用于实时数据统计场景,比如页面的浏览量统计、在线用户数等。在这类场景中,数据的准确性要求不高,但需要快速读写。

适用场景:

实时在线用户统计
页面浏览量统计
课程实时访问量
Redis 适合使用的场景总结:
数据缓存:频繁查询但不常更新的数据。
会话管理:分布式系统中的用户会话共享。
排行榜、点赞:需要高效的计数和排名操作。
限流防护:限制用户的频繁操作,防止攻击。
消息队列:处理异步任务,提高系统性能。
分布式锁:保证分布式系统中的互斥操作。
实时统计:用于快速统计和展示实时数据。
Redis 能在这些场景下大大提升性能,同时减少数据库压力和提高系统的扩展性。在设计系统时,可以结合业务特点,选择合适的场景应用 Redis。

问题:那我想问个底层问题,就是redis每次是通过exe启动的,那么他这些数据在我关闭exe的时候还存着吗,还是说redis存的东西是放在本地

Redis 是一个内存数据库,默认情况下,数据是存储在内存中的,所以当你关闭 Redis 进程(例如关闭 redis-server.exe)时,内存中的数据会丢失。但是 Redis 提供了多种持久化机制,可以将数据保存到磁盘上,这样即使 Redis 进程关闭或重启,数据仍然可以恢复。

Redis 的持久化机制
Redis 提供两种常见的持久化机制:

1. RDB(Redis DataBase)快照
Redis 可以周期性地将内存中的数据保存到磁盘上,生成一个 .rdb 文件。这种机制称为 RDB 持久化。RDB 是 Redis 的一种二进制快照文件,定期将整个数据集进行快照保存。

特点:

适合灾难恢复:可以定期保存 Redis 数据到本地,减少丢失数据的风险。
恢复速度快:RDB 文件较小,Redis 启动时加载 RDB 文件,恢复内存中的数据。
数据可能丢失:因为快照是周期性生成的,所以在 Redis 崩溃或关闭后,可能丢失最近一次快照后的数据。
配置方式: 你可以在 redis.conf 文件中配置 RDB 持久化。常见配置如下:

bash
复制代码
save 900 1   # 在 900 秒内如果有至少 1 次写操作,生成快照
save 300 10  # 在 300 秒内如果有至少 10 次写操作,生成快照
save 60 10000 # 在 60 秒内如果有至少 10000 次写操作,生成快照
手动触发快照: 你也可以手动触发快照,使用 Redis 命令:

bash
复制代码
SAVE   # 同步保存快照
BGSAVE # 异步保存快照
2. AOF(Append-Only File)持久化
AOF 持久化记录每个对 Redis 的写操作(例如 SET、HSET 等),并将这些操作以追加的方式写入到日志文件中。Redis 重启时可以通过重放这些操作来恢复数据。

特点:

数据丢失更少:AOF 的数据可以非常接近实时写入,最多丢失几毫秒的数据。
文件体积大:由于每次写操作都记录,AOF 文件可能比 RDB 文件大很多。
恢复较慢:恢复数据时需要重放所有的命令,所以恢复过程比 RDB 慢。
配置方式: 你可以在 redis.conf 中开启 AOF 持久化:

bash
复制代码
appendonly yes            # 启用 AOF
appendfilename "appendonly.aof"  # AOF 文件名
AOF 持久化模式:

bash
复制代码
appendfsync always      # 每个写操作都立即同步到磁盘(性能差,但数据最安全)
appendfsync everysec    # 每秒同步一次(默认,平衡了性能和数据安全)
appendfsync no          # 让操作系统自行决定何时同步(性能最好,但数据安全性差)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值