iis服务器助手广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >基于Redis的List实现特价商品列表功能
  • 176
分享到

基于Redis的List实现特价商品列表功能

2024-04-02 19:04:59 176人浏览 八月长安
摘要

目录 1、场景分析2、分析3 、具体实现3.1 ProductListService类3.2 商品的数据接口的定义和展示及分页3.3 定时任务4、解决商品列表存在的缓存击穿

 1、场景分析

淘宝京东的特价商品列表,

商品特点:

  • 商品有限,并发量非常的大。
  • 考虑分页

传统解决方案:数据库db,

但是在如此大的并发量的情况下,不可取。

一般会采用Redis来处理。这些特价商品的数据不多,而且redis的list本身也支持分页。是天然处理这种列表的最佳选择解决方案。

2、分析

采用list数据,因为list数据结构有:lrange key 0 -1 可以进行数据的分页。


127.0.0.1:6379> lpush products p1 p2 p3 p4 p5 p6 p7 p8 p9 p10
(integer) 10
127.0.0.1:6379> lrange products 0 1
1) "p10"
2) "p9"
127.0.0.1:6379> lrange products 2 3
1) "p8"
2) "p7"
127.0.0.1:6379> lrange products 4 5
1) "p6"
2) "p5"

3 、具体实现

淘宝,京东的热门商品在双11的时候,可能有100多w需要搞活动:程序需要5分钟对特价商品进行刷新。

3.1 ProductListService类

  •  初始化的活动的商品信息100个(从数据库去查询)

@PostContrcut使用

  •  查询产品列表信息

换算的分页的起始位置和结束位置


package com.example.service;

import com.example.entity.Product;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;


@Service
@Slf4j
public class ProductListService {

    @Autowired
    private RedisTemplate redisTemplate;

    // 数据热加载
    @PostConstruct
    public void initData(){
        log.info("启动定时加载特价商品到redis的list中...");
        new Thread(() -> runCourse()).start();
    }

    public void runCourse() {
        while (true) {
            // 从数据库中查询出特价商品
            List<Product> productList = this.findProductsDB();
            // 删除原来的特价商品
            this.redisTemplate.delete("product:hot:list");
            // 把特价商品添加到集合中
            this.redisTemplate.opsForList().leftPushAll("product:hot:list", productList);
            try {
                // 每隔一分钟执行一次
                Thread.sleep(1000 * 60);
                log.info("定时刷新特价商品....");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    
    public List<Product> findProductsDB() {
        //List<Product> productList = productMapper.selectListHot();
        List<Product> productList = new ArrayList<>();
        for (long i = 1; i <= 100; i++) {
            Product product = new Product();
            product.setId((long) new Random().nextInt(1000));
            product.setPrice((double) i);
            product.setTitle("特价商品" + (i));
            productList.add(product);
        }
        return productList;
    }

}

3.2 商品的数据接口的定义和展示及分页


package com.example.controller;

import com.example.entity.Product;
import com.example.service.ProductListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.WEB.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
public class ProductListController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductListService productListService;

    @GetMapping("/findProducts")
    public List<Product> findProducts(int pageNo, int pageSize) {

        // 从那个集合去查询
        String key = "product:hot:list";
        // 分页的开始结束的换算
        if (pageNo <= 0) pageNo = 1;
        int start = (pageNo - 1) * pageSize;
        // 计算分页的结束页
        int end = start + pageSize - 1;

        // 根据redis的api去处理分页查询对应的结果
        try {
            List<Product> productList = this.redisTemplate.opsForList().range(key, start, end);
            if (CollectionUtils.isEmpty(productList)) {
                //todo: 查询数据库,存在缓存击穿的情况,大量的并发请求进来,可能把数据库冲
                productList = productListService.findProductsDB();
            }
            return productList;

        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

}

3.3 定时任务


@Configuration      // 主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 开启定时任务
public class SaticScheduleTask {
    // 添加定时任务
    @Scheduled(cron = "* 0/5 * * * ?")
    // 或直接指定时间间隔,例如:5秒
    // @Scheduled(fixedRate=5000)
    private void configureTasks() {
        System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
    }
}

4、解决商品列表存在的缓存击穿问题

 4.1 如何引起的缓存击穿的情况


public void runCourse() {
        while (true) {
            // 从数据库中查询出特价商品
            List<Product> productList = this.findProductsDB();
            // 删除原来的特价商品
            this.redisTemplate.delete("product:hot:list");
            // 把特价商品添加到集合中 需要时间
            this.redisTemplate.opsForList().leftPushAll("product:hot:list", productList);
            try {
                // 每隔一分钟执行一遍
                Thread.sleep(1000 * 60);
                log.info("定时刷新特价商品....");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

出现原因:

  • 特价商品的数据更换需要时间,刚好特价商品还没有放入到redis缓存中。
  • 查询特价商品的并发量非常大,可能程序还正在写入特价商品到缓存中,这时查询缓存根本没有数据,就会直接冲入数据库中去查询特价商品。可能造成数据库冲垮。这个就叫做:缓存击穿

4.2 解决方案

主从轮询

可以开辟两块redis的集合空间A和B。定时器在更新缓存的时候,先更新B缓存然后再更新A缓存

一定要按照特定顺序来处理。


package com.example.service;

import com.example.entity.Product;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;


@Service
@Slf4j
public class ProductListService {

    @Autowired
    private RedisTemplate redisTemplate;

    // 数据热加载
    @PostConstruct
    public void initData(){
        log.info("启动定时加载特价商品到redis的list中...");
        new Thread(() -> runCourse()).start();
    }

    public void runCourse() {
        while (true) {
            // 从数据库中查询出特价商品
            List<Product> productList = this.findProductsDB();

            // 删除原来的特价商品
            this.redisTemplate.delete("product:hot:slave:list");
            // 把特价商品添加到集合中
            this.redisTemplate.opsForList().leftPushAll("product:hot:slave:list", productList);// 删除原来的特价商品

            this.redisTemplate.delete("product:hot:master:list");
            // 把特价商品添加到集合中
            this.redisTemplate.opsForList().leftPushAll("product:hot:master:list", productList);

//            // 删除原来的特价商品
//            this.redisTemplate.delete("product:hot:list");
//            // 把特价商品添加到集合中
//            this.redisTemplate.opsForList().leftPushAll("product:hot:list", productList);
            try {
                // 每隔一分钟执行一次
                Thread.sleep(1000 * 60);
                log.info("定时刷新特价商品....");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    
    public List<Product> findProductsDB() {
        //List<Product> productList = productMapper.selectListHot();
        List<Product> productList = new ArrayList<>();
        for (long i = 1; i <= 100; i++) {
            Product product = new Product();
            product.setId((long) new Random().nextInt(1000));
            product.setPrice((double) i);
            product.setTitle("特价商品" + (i));
            productList.add(product);
        }
        return productList;
    }

}

package com.example.controller;

import com.example.entity.Product;
import com.example.service.ProductListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
public class ProductListController {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductListService productListService;

    @GetMapping("/findProducts")
    public List<Product> findProducts(int pageNo, int pageSize) {

        // 从那个集合去查询

        String master_key = "product:hot:master:list";
        String slave_key = "product:hot:slave:list";

        String key = "product:hot:list";
        // 分页的开始结束的换算
        if (pageNo <= 0) pageNo = 1;
        int start = (pageNo - 1) * pageSize;
        // 计算分页的结束页
        int end = start + pageSize - 1;

        // 根据redis的api去处理分页查询对应的结果
        try {

            List<Product> productList = this.redisTemplate.opsForList().range(master_key, start, end);

//            List<Product> productList = this.redisTemplate.opsForList().range(key, start, end);
            if (CollectionUtils.isEmpty(productList)) {
                // todo: 查询数据库,存在缓存击穿的情况,大量的并发请求进来,可能把数据库冲

                productList = this.redisTemplate.opsForList().range(slave_key, start, end);

//                productList = productListService.findProductsDB();
            }
            return productList;

        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

}

到此这篇关于基于Redis的List实现特价商品列表的文章就介绍到这了,更多相关redis list商品列表内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 基于Redis的List实现特价商品列表功能

本文链接: https://www.lsjlt.com/news/133951.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 基于Redis的List实现特价商品列表功能
    目录 1、场景分析2、分析3 、具体实现3.1 ProductListService类3.2 商品的数据接口的定义和展示及分页3.3 定时任务4、解决商品列表存在的缓存击穿...
    99+
    2024-04-02
  • Vueelement商品列表的增删改功能实现
    目录介绍 基本信息上传主图商品信息vue富文本编辑器的配置最后提交数据介绍  整体和用户列表 类似 功能步骤有: 面包屑导航外部是大的卡片组件搜索商品 添加商品...
    99+
    2024-04-02
  • vue怎么实现点击选中商品列表的功能
    最近在做一个电商网站,需要实现点击选中商品列表的功能,借着这个机会,学习了一下Vue框架。在Vue中,实现点击选中列表非常简单,只需要使用Vue提供的v-on指令和v-bind指令即可。首先,在模板中定义一个商品列表,每个商品后面都有一个c...
    99+
    2023-05-14
  • vue如何实现点击选中商品列表的功能
    本篇内容主要讲解“vue如何实现点击选中商品列表的功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue如何实现点击选中商品列表的功能”吧!在Vue中,实现点击选中列表非常简单,只需要使用Vu...
    99+
    2023-07-05
  • 基于Vue如何实现商品主图放大镜功能
    这篇文章主要介绍基于Vue如何实现商品主图放大镜功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实现原理放大镜的原理用一句话概括,就是根据小图上的鼠标位置去定位大图。图1 原理图(...
    99+
    2024-04-02
  • 基于vue实现循环滚动列表功能
    注意:需要给父容器一个height和:data='Array'和overfolw:hidden;左右滚动需要给ul容器一个初始化 css width。 先来介绍该组件的用法: 1.安...
    99+
    2024-04-02
  • 微信小程序如何实现商品列表跳转商品详情页功能
    目录引言1.1实现首页页面2.1实现调跳转到手机详情页总结引言 模仿京东小程序,实现下列功能 首页包含了手机图片,手机的描述,手机的价格,购物车图标首页显示两行文字,多余的文字隐藏,...
    99+
    2024-04-02
  • 微信小程序怎么实现商品列表跳转商品详情页功能
    这篇文章主要介绍“微信小程序怎么实现商品列表跳转商品详情页功能”,在日常操作中,相信很多人在微信小程序怎么实现商品列表跳转商品详情页功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”微信小程序怎么实现商品列表...
    99+
    2023-06-30
  • Redis实现商品秒杀功能页面流程
    目录全局唯一ID 业务逻辑分析代码实现优惠券秒杀业务逻辑分析代码实现定量商品多卖问题业务逻辑分析乐观锁与悲观锁乐观锁代码实现一个用户限买一单业务逻辑分析代码实现全局唯一ID...
    99+
    2024-04-02
  • 如何实现基于css3的列表toggle特效
    这篇文章主要讲解了“如何实现基于css3的列表toggle特效”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何实现基于css3的列表toggle特效”吧!...
    99+
    2024-04-02
  • PHP商城中的商品管理功能实现
    随着互联网的不断发展和进步,线上购物成为了现代人不可或缺的生活方式。而对于电商商城而言,商品管理是最为重要的一项功能之一。PHP商城中的商品管理功能,实现起来非常的简单方便,下面就来详细介绍一下。商品的添加在商品管理界面中,管理员可以选择添...
    99+
    2023-05-22
    PHP 商城 商品管理功能
  • Redis基于Bitmap实现用户签到功能
    目录功能分析更多应用场景总结 参考资料 很多应用上都有用户签到的功能,尤其是配合积分系统一起使用。现在有以下需求: 签到1天得1积分,连续签到2天得2积分,3天得3积分,3...
    99+
    2024-04-02
  • PHP商城中的商品租赁功能实现
    随着人们生活水平的提高,逐渐有了更高的生活品质和消费需求,特别是对于一些高昂的商品,很多人都想尝试,但是却无法承担高昂的购买费用,这时商品租赁就成了一个非常不错的选择。随着网络技术、支付体系等方面的不断提升,电子商务平台已经成为了人们进行商...
    99+
    2023-05-21
    PHP 商城 租赁功能
  • Pythonr基于selenium如何实现不同商城的商品价格差异分析系统
    目录1. 前言2、程序设计流程2.1 需求分析:2.2 认识 selenium2.3 功能函数设计3. 总结1. 前言 selenium 原本是一款自动化测试工具,因其出色的页面数据...
    99+
    2024-04-02
  • Pythonr基于selenium怎么实现不同商城的商品价格差异分析系统
    这篇文章主要介绍了Pythonr基于selenium怎么实现不同商城的商品价格差异分析系统的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Pythonr基于selenium怎么实现不同商城的商品价格差异分析系统文...
    99+
    2023-06-29
  • 基于Redis位图实现用户签到功能
    场景需求 适用场景如签到送积分、签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等。 如果连续签到中断,则重...
    99+
    2024-04-02
  • Android基于BaseExpandableListAdapter实现的二级列表仿通话记录功能详解
    本文实例讲述了Android基于BaseExpandableListAdapter实现的二级列表仿通话记录功能。分享给大家供大家参考,具体如下:android SDK中带有这样类似的例子,但是那个还是静态数据,没有实际应用价值,参考意义不大...
    99+
    2023-05-30
    android baseexpandablelistadapter 通话记录
  • 基于Redis实现抽奖功能及问题小结
    1、分析 公司年底要做年会所有的员工都要参与抽奖的环节 平台的产品要进行抽奖活动 这个时候我们可以利用redis中的set集合中的spop来实现。 特征:抽奖成功...
    99+
    2024-04-02
  • 基于Redis延迟队列的实现代码
    使用场景 工作中大家往往会遇到类似的场景: 1.对于红包场景,账户 A 对账户 B 发出红包通常在 1 天后会自动归还到原账户。 2.对于实时支付场景,如果账户 A 对商户 S 付款...
    99+
    2024-04-02
  • 基于Redis实现阻塞队列的方式
    日常需求开发过程中,不免会遇到需要通过代码进行异步处理的情况,比如批量发送邮件,批量发送短信,数据导入,为了减少用户的等待,不希望一直菊花转啊转,因此需要进行异步处理,做法就是讲要处...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作