Spring Boot Redis 应用场景

爱被打了一巴掌 2024-03-27 16:44 109阅读 0赞

1. 前言

Redis 其实就是基于内存的键值型数据库,与 Oracle 、 SQL Server 、 MySQL 等传统关系型数据库相比,它最大的优势就是读写速度快。

到底有多快呢,我曾经使用 Windows 版本的 Redis 进行过真实测试,每秒读写次数均可以超过1 万次。据了解 Redis 每秒的读写操作次数其实是可以达到 10 万多次的。

所以 Redis 非常适合作为热点数据的缓存,这个我们在上一节已经演示过了。本节通过其他两个实际场景来演示下 Spring Boot 中如何应用 Redis 。

  • 网站的访问次数
  • 热门商品排行榜

2. 网站的访问次数

大型网站访问次数的查询、更新非常频繁,如果通过关系数据库读写,无疑会耗费大量的性能,而使用 Redis 可以大幅提高速度并降低对关系数据库的消耗。

2.1 使用 Spring Initializr 创建项目

Spring Boot 版本选择 2.2.5 ,Group 为 com.5axxw , Artifact 为 spring-boot-redis,生成项目后导入 Eclipse 开发环境。

2.2 引入项目依赖

我们引入 Web 项目依赖与 Redis 依赖。

实例:

  1. <!-- Web 依赖 -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <!-- Redis 依赖 -->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-data-redis</artifactId>
  10. </dependency>

2.3 配置 Redis 数据库连接

修改 application.properties 配置文件内容如下。

实例:

  1. # Redis库的编号
  2. spring.redis.database=0
  3. # Redis实例地址
  4. spring.redis.host=127.0.0.1
  5. # Redis实例端口号,默认6379
  6. spring.redis.port=6379
  7. # Redis登录密码
  8. spring.redis.password=Easy@0122
  9. # Redis连接池最大连接数
  10. spring.redis.jedis.pool.max-active=10
  11. # Redis连接池最大空闲连接数
  12. spring.redis.jedis.pool.max-idle=10
  13. # Redis连接池最小空闲连接数
  14. spring.redis.jedis.pool.min-idle=0

2.4 开发网站访问统计服务类

开发网站访问统计服务类,在第 1 次获取访问次数时初始化次数为 0 ,后续每次访问次数加 1 。

实例:

  1. /**
  2. * 网站访问统计服务类
  3. */
  4. @Service
  5. public class VisitService {
  6. // 设定访问次数Redis键名
  7. private final static String KEY = "visit_count";
  8. // 注入redisTemplate操作Redis
  9. @Autowired
  10. private RedisTemplate<String, String> redisTemplate;
  11. // 获取当前访问次数
  12. public String getCurrentCount() {
  13. String count = redisTemplate.opsForValue().get(KEY);
  14. if (count == null || "".equals(count)) {
  15. redisTemplate.opsForValue().set(KEY, "0");
  16. return "0";
  17. }
  18. return count;
  19. }
  20. // 访问次数加1
  21. public void addCount() {
  22. redisTemplate.opsForValue().increment(KEY, 1);
  23. }
  24. }

2.5 并发访问测试

我们通过测试类发起并发访问测试,代码如下:

实例:

  1. /**
  2. * 访问统计服务测试
  3. */
  4. @SpringBootTest
  5. class VisitServiceTest {
  6. private Logger logger = LoggerFactory.getLogger(this.getClass());
  7. @Autowired
  8. private VisitService visitService;
  9. @Test
  10. void test() {
  11. logger.info("访问次数:{}", visitService.getCurrentCount());
  12. // 使用线程池快速发起10000次访问
  13. ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  14. for (int i = 0; i < 10000; i++) {
  15. cachedThreadPool.execute(new Runnable() {
  16. public void run() {
  17. visitService.addCount();
  18. }
  19. });
  20. }
  21. }
  22. }

此时我们通过 Redis 客户端发现 visit_count 的值如下:

并发访问测试结果

Tips:Redis 中的操作都是原子性的,要么执行,要么不执行,在高并发场景下依然可以准确的进行计数,关键是速度还非常之快!

3. 热门商品排行榜

如果是大型网站,时刻有很多用户在访问网页,对热门商品排行榜的访问频率是非常恐怖的。

我们可以通过定时器,定时从关系数据库中取出热门商品数据放入 Redis 缓存,用户访问网页时,直接从缓存中获取热门商品数据。这将大大提高响应速度,并降低对关系数据库的性能损耗。

3.1 定义商品类

我们简单的定义一个商品类,便于展现商品排行榜数据。

实例:

  1. /**
  2. * 商品类
  3. */
  4. public class GoodsDo {
  5. /**
  6. * 商品id
  7. */
  8. private Long id;
  9. /**
  10. * 商品名称
  11. */
  12. private String name;
  13. /**
  14. * 商品价格
  15. */
  16. private String price;
  17. /**
  18. * 商品图片
  19. */
  20. private String pic;
  21. // 省略get set方法
  22. }

3.2 开发商品排行榜服务类

开发商品排行榜服务类,负责从数据库查询最新排行榜信息,并更新到 Redis ,以及从 Redis 中取出排行榜信息。

实例:

  1. /**
  2. * 商品排行榜服务类
  3. */
  4. @Service
  5. public class GoodsRankService {
  6. // 设定商品排行榜Redis键名
  7. private final static String KEY = "goods_rank";
  8. // 注入redisTemplate操作Redis
  9. @Autowired
  10. private RedisTemplate<String, String> redisTemplate;
  11. // 更新Redis缓存的排行榜
  12. public void updateRankList() throws JsonProcessingException {
  13. // 此处直接定义商品排行榜,真实场景应为从数据库获取
  14. List<GoodsDo> rankList = new ArrayList<GoodsDo>();
  15. GoodsDo goods = new GoodsDo();
  16. goods.setId(1L);
  17. goods.setName("鸡蛋" + new Date());// 添加时间信息,以便测试缓存更新了
  18. rankList.add(goods);
  19. // 将rankList序列化后写入Reidis
  20. ObjectMapper mapper = new ObjectMapper();
  21. redisTemplate.opsForValue().set(KEY, mapper.writeValueAsString(rankList));
  22. }
  23. // 获取Redis缓存的排行榜
  24. public List<GoodsDo> getRandkList() throws JsonMappingException, JsonProcessingException {
  25. ObjectMapper mapper = new ObjectMapper();
  26. return mapper.readValue(redisTemplate.opsForValue().get(KEY), List.class);
  27. }
  28. }

3.3 通过定时器更新排行榜

为启动类添加 @EnableScheduling 注解,以便开启定时任务,然后编写 RankListUpdateTask 类定时刷新排行榜。

实例:

  1. /**
  2. * 排行榜更新任务
  3. */
  4. @Component
  5. public class RankListUpdateTask {
  6. @Autowired
  7. private GoodsRankService goodsRankService;
  8. /**
  9. * 容器启动后马上执行,且每1秒执行1次
  10. */
  11. @Scheduled(initialDelay = 0, fixedRate = 1000)
  12. public void execute() throws InterruptedException, JsonProcessingException {
  13. goodsRankService.updateRankList();
  14. }
  15. }

3.4 开发控制器方法

我们还需要一个控制器方法,用于演示获取商品列表的结果。

实例:

  1. @RestController
  2. public class GoodsRankController {
  3. @Autowired
  4. private GoodsRankService goodsRankService;
  5. @GetMapping("getRankList")
  6. public List getRankList() throws Exception {
  7. return goodsRankService.getRandkList();
  8. }
  9. }

3.5 测试

运行启动类,然后访问 http://127.0.0.1:8080/getRankList ,结果如下:

  1. [{"id":1,"name":"鸡蛋Thu May 28 22:47:33 CST 2020","price":null,"pic":null}]

稍等会再次访问,结果如下:

  1. [{"id":1,"name":"鸡蛋Thu May 28 22:48:09 CST 2020","price":null,"pic":null}]

说明我们设计的缓存机制生效了。

4. 小结

开发的项目多了,越来越能体会,传统数据库访问速度是限制系统性能的最大瓶颈。

而 Redis 基于内存的特性,可以极大地提高读写效率,使用得当,往往使系统性能有质的提升。

Spring Boot 可以非常方便地集成 Redis ,当我们在项目开发中遇到访问频率非常高的热点数据时,可以优先考虑使用 Redis 进行存储操作。

发表评论

表情:
评论列表 (有 0 条评论,109人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Redis应用场景

    转载:[Redis应用场景][Redis] NoSQL主要用于解决以下几种问题   1.少量数据存储,高速读写访问。此类产品通过数据全部in-momery 的方式来保证高速

    相关 redis应用场景

    1、缓存系统 数据可以直接从cache(也就是redis)里面获取 2、计数器 微博的评论数,转发数等,可以用redis的increase方法实现;很多视屏播放系统也是可

    相关 redis应用场景

     毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结

    相关 Redis应用场景

    1.  MySql+Memcached架构的问题 Memcached采用客户端\-服务器的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式