Redis框架(十):大众点评项目 订单功能 Redis实现全局唯一ID、 秒杀基本环境

news2024/12/30 2:29:17

大众点评项目 订单功能 秒杀基本环境

  • 需求:订单功能 秒杀基本环境
  • Redis实现全局唯一ID
  • 业务实现
  • 代码总览
  • 总结

SpringCloud章节复习已经过去,新的章节Redis开始了,这个章节中将会回顾Redis实战项目 大众点评
主要依照以下几个原则

  1. 基础+实战的Demo和Coding上传到我的代码仓库
  2. 在原有基础上加入一些设计模式,stream+lamdba等新的糖
  3. 通过DeBug调试,进入组件源码去分析底层运行的规则和设计模式

代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
Redis优化-链接: RedisLightningDealsProject
在这里插入图片描述

需求:订单功能 秒杀基本环境

商品分析
在点评项目中,存在了优惠券这种商品,优惠券分成了两种

  1. 普通优惠券:无限量抢购,无时间限制
  2. 秒杀优惠券:限量,限时

在这里插入图片描述

分析表结构

在这里插入图片描述
这里是基本优惠券表
在这里插入图片描述
这里是秒杀优惠券表,本身就是基本优惠券,多了一些字段

在这里插入图片描述

Redis实现全局唯一ID

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

@Component
public class RedisIDProductor {
    /**
     * 我的当前时间号
     */
    private static final long BEGIN_TIMESTAMP = 1670847120L;

    /**
     * 序列号位数
     */
    private static final int COUNT_BITS = 32;

注入Redis

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public RedisIDProductor(StringRedisTemplate stringRedisTemplate){
        this.stringRedisTemplate = stringRedisTemplate;
    }

通过Redis自增id创建,这里分成三个步骤

  1. 生成时间戳,就是时间差值,32位
  2. 生成Redis序列号,通过Redis的有序自增 ,32位
  3. 通过位运算进行拼接!
    public long nextId(String keyPrefix){

// 生成时间戳,就是时间差值,32位
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIMESTAMP;
    
 // 生成Redis序列号,通过Redis的有序自增  ,32位
        String curTime = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        Long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + curTime);

 // 通过位运算进行拼接!
        return timestamp<<COUNT_BITS | count;
    }

业务实现

先通过PostMan提交post请求,更新优惠券信息

在这里插入图片描述

{
    "shopId":1,
    "title":"100元代金券",
    "subTitle":"周一至周日均可使用",
    "rules":"全场通用\\n无需预约\\n可无限叠加\\不兑现、不找零\\n仅限堂食",
    "payValue":8000,
    "actualValue":10000,
    "type":1,
    "stock":100,
    "beginTime":"2022-12-12T10:09:17",
    "endTime":"2022-12-26T14:09:04"
}

DB查看优惠券信息
在这里插入图片描述

通过请求的URL区修改对应的方法

@Service
@Slf4j
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    private ISeckillVoucherService seckillVoucherService;

    @Resource
    private RedisIDProductor redisIDProductor;

由于是对多个表的操作,
**@Transactional **保证了事务

    @Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {

// voucher:通过id去查到底是那种优惠券
        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);

        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            return Result.fail("秒杀尚未开始");
        }

        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已经结束");
        }

        if (voucher.getStock() < 1) {
            return Result.fail("库存不足");
        }

这里是通过MP本身的API直接进行库存的增减

        //验证结束,扣减库存
        boolean flag = seckillVoucherService.update()
                .setSql("stock = stock - 1")
                .eq("voucher_id", voucherId)
                .update();

        if (!flag) {
            return Result.fail("库存不足");
        }

链式API封装订单信息,将其保存到订单表中

        //封装订单
        VoucherOrder voucherOrder = new VoucherOrder();
        Long userId = UserHolder.getUser().getId();
        long orderId = redisIDProductor.nextId("order");
        //订单Id、用户Id、优惠券Id
        voucherOrder.setId(orderId).setUserId(userId).setVoucherId(voucherId);
        save(voucherOrder);

        return Result.ok(orderId);

    }
}

代码总览

@RestController
@RequestMapping("/voucher-order")
public class VoucherOrderController {

    @Resource
    private IVoucherOrderService voucherOrderService;

    @PostMapping("seckill/{id}")
    public Result seckillVoucher(@PathVariable("id") Long voucherId) {
        return voucherOrderService.seckillVoucher(voucherId);
//        return Result.fail("功能未完成");
    }
}
public interface IVoucherOrderService extends IService<VoucherOrder> {

    Result seckillVoucher(Long voucherId);
}
@Service
@Slf4j
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    private ISeckillVoucherService seckillVoucherService;

    @Resource
    private RedisIDProductor redisIDProductor;

    @Override
    @Transactional
    public Result seckillVoucher(Long voucherId) {

        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);

        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            return Result.fail("秒杀尚未开始");
        }

        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已经结束");
        }

        if (voucher.getStock() < 1) {
            return Result.fail("库存不足");
        }

        //验证结束,扣减库存
        boolean flag = seckillVoucherService.update()
                .setSql("stock = stock - 1")
                .eq("voucher_id", voucherId)
                .update();

        if (!flag) {
            return Result.fail("库存不足");
        }

        //封装订单
        VoucherOrder voucherOrder = new VoucherOrder();
        Long userId = UserHolder.getUser().getId();
        long orderId = redisIDProductor.nextId("order");
        //订单Id、用户Id、优惠券Id
        voucherOrder.setId(orderId).setUserId(userId).setVoucherId(voucherId);
        save(voucherOrder);

        return Result.ok(orderId);

    }
}


@Service
public class VoucherServiceImpl extends ServiceImpl<VoucherMapper, Voucher> implements IVoucherService {

    @Resource
    private ISeckillVoucherService seckillVoucherService;

    @Override
    public Result queryVoucherOfShop(Long shopId) {
        // 查询优惠券信息
        List<Voucher> vouchers = getBaseMapper().queryVoucherOfShop(shopId);
        // 返回结果
        return Result.ok(vouchers);
    }

    @Override
    @Transactional
    public void addSeckillVoucher(Voucher voucher) {
        // 保存优惠券
        save(voucher);
        // 保存秒杀信息
        SeckillVoucher seckillVoucher = new SeckillVoucher();
        seckillVoucher.setVoucherId(voucher.getId());
        seckillVoucher.setStock(voucher.getStock());
        seckillVoucher.setBeginTime(voucher.getBeginTime());
        seckillVoucher.setEndTime(voucher.getEndTime());
        seckillVoucherService.save(seckillVoucher);
    }


}

总结

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

揭秘!全球2022年Salesforce不同招聘职位的平均薪资

Salesforce可以说是发展最快的企业软件公司。此外&#xff0c;还一直被评选为全球最佳工作场所之一&#xff0c;2021年赢得了Glassdoor评选的最佳工作场所&#xff0c;并且在《财富》杂志的100家最佳工作公司中排名第四。除了非常重视员工福利&#xff0c;强调工作与生活的平衡…

在WSL中配置GPU环境

首先需要明确一点&#xff0c;虽然我们通过安装WSL获得了linux开发环境&#xff0c;但是我们最终使用的GPU还是在windows当中的&#xff0c;所以还是需要在系统中安装对应的驱动。 第一步&#xff1a;在window上根据显卡型号和版本安装驱动 这里参考之前的步骤就行 第二步&a…

HPC走出全新路线:《开放架构HPC技术与生态白皮书》注解

文|智能相对论 作者|叶远风 数字经济大时代&#xff0c;创新驱动大环境&#xff0c;HPC已不再是阳春白雪&#xff0c;而受到越来越多人的关注。 HPC&#xff0c;即High Performance Computing&#xff0c;高性能计算。对普通人来说&#xff0c;没有听过HPC&#xff0c;但肯定…

使用docker-compose搭建mysql主从复制

使用docker-compose搭建mysql主从复制&#xff1a; Mysql的主从【快速】搭建编写脚本编写 master.sh 脚本编写 slave.sh 脚本编写docker-compose.yml文本测试阶段主从同步效果主从环境重启容器被删除&#xff0c;重新启动从节点关闭&#xff0c;主节点继续写入数据从节点删除&a…

[附源码]计算机毕业设计的云网盘设计Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

阻塞队列BlockingQueue与同步队列SynchronousQueue

阻塞队列&#xff08;BlockingQueue&#xff09; 什么情况下我们会使用阻塞队列&#xff1f; 多线程并发处理&#xff0c;线程池&#xff01; 使用队列 添加 移除 BlockingQueue四组API 方式有返回值&#xff0c;抛出异常 有返回值&#xff0c;不抛出异常 阻塞等待 超时等待 …

Kubelet v1.25.x源码——StatusManager

1. 环境说明 Kubernetes源码版本&#xff1a;remotes/origin/release-1.25 Kubernetes编译出来的Kubelet版本&#xff1a;Kubernetes v1.24.0-beta.0.2463ee7799bab469d7 Kubernetes集群实验环境&#xff1a;使用Kubernetes v1.25.4二进制的方式搭建了一个单节点集群 K8S 单节…

Linux redhat8.0 NFS共享目录

简介&#xff1a; NFS允许一个系统在网络上与它人共享目录和文件。通过使用NFS&#xff0c;用户和程序可以像访问本地文件一样访问远端系统上的文件。 作用&#xff1a; 多个机器共享一台CDROM或者其他设备。这对于在多台机器中安装软件来说更加便宜跟方便。 员工都可以操作…

流辰信息技术企业凭匠心,助力企业打造专属低代码解决方案!

从建立之初开始&#xff0c;流辰信息技术企业就凭借一股热劲和对低代码开发平台的执着热爱精神&#xff0c;在业界打磨升级&#xff0c;成为众多新老客户朋友青睐和信任的服务商。 在稳定发展的近些年中&#xff0c;流辰信息一直信奉品质和服务是紧跟市场发展步伐的法宝&#x…

maven工程,mybatis,spring

maven 简介&#xff1a;Maven主要用于解决导入依赖于Java类的jar和编译Java项目的主要问题&#xff0c;其使用pom文件将自动管理下载的jar包 创建maven工程 1. groupid:包名 artifactid:工程名 location:存放位置 2.结构 工程目录结构&#xff1a;srcmain主程序区java后端代…

ARM的八种工作模式

ARM有八种工作模式&#xff0c;有些处理器可能是七种&#xff0c;这个要看处理器的版本&#xff0c;早期的处理器如ARM9有七种工作模式&#xff0c;到了后来的Cortex系列新增了一种Secure Monitor模式。对工作模式的理解需要记住以下三点&#xff1a; 不同模式拥有不同的权限不…

基于冲突搜索算法的多机器人路径规划(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Java Request学习笔记

1.获取请求部分的信息方法&#xff1a; Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置响应的内容为html&#xff0c;指定编码为utf-8response.setContentType("text/html;…

如何利用ArcGIS探究环境与生态因子对水体、土壤、大气污染物等影响

如何利用ArcGIS实现电子地图可视化表达&#xff1f;如何利用ArcGIS分析空间数据&#xff1f;如何利用ArcGIS提升SCI论文的层次&#xff1f;制图是地理数据展现的直观形式&#xff0c;也是地理数据应用的必要基础。本次课程从ArcGIS的基本操作、ArcGIS 的空间数据分析及ArcGIS 的…

Biotin-PEG-Fluorescein,FITC-PEG-Biotin,荧光素peg生物素用于纳米粒子

英文名称&#xff1a;FITC-PEG-Biotin&#xff0c;Biotin-PEG-Fluorescein 中文名称&#xff1a;荧光素-聚乙二醇-生物素 FITC-PEG生物素是一种含有荧光素染料和生物素基团的线性异生物功能PEG试剂。荧光素通常被称为FITC&#xff0c;是生物学中常用的荧光示踪剂&#xff0c;…

[附源码]Node.js计算机毕业设计电影网站系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Flask从入门到放弃三(g对象、Flask-Session的使用、Flask集成Mysql、Wtforms、信号)

文章标题一、g对象二、Flask-Session使用三、数据库连接池1&#xff09;Flask中集成mysql2&#xff09;上面代码存在的问题3&#xff09;使用数据库连接池4&#xff09;压力测试四、WTForms1&#xff09;Python代码2&#xff09;Hmtl代码五、信号一、g对象 介绍 g对象全称glo…

java instanceof关键字详解

instanceof描述 将从操作数堆栈中弹出objectref&#xff0c;它必须是引用类型。无符号indexbyte1和indexbyte2用于将索引构造到当前类的运行时常量池中&#xff08;2.6&#xff09;&#xff0c;其中索引的值为&#xff08;indexbyte1<<8&#xff09;|indexbyte2.索引处的…

node文件上传和下载

node文件上传和下载 一、准备项目 npm install -g express-generator express upload-download然后用vscode打开&#xff0c;安装依赖包&#xff0c;在装一个nodemon #安装依赖npm i# 安装nodemonpm i nodemon -g修改启动命令 启动项目&#xff0c;访问localhost&#xff1a;…

WebDAV之葫芦儿·派盘 + CloudBeats

CloudBeats 支持WebDAV方式连接葫芦儿派盘。 推荐一款手机云端音乐播放器,可以直接播放云盘中的音乐,不占用手机内存,同时也可以播放本地的音频文件,自动扫描,支持离线播放,可以自由创建音乐播放列表。 CloudBeats无需网络即可运行。将专辑,播放列表,文件夹或文件下…