SpringBoot+RabbitMQ+Redis实现商品秒杀的示例代码

目录
  • 业务分析
  • 创建表
  • 功能实现
    • 1.用户校验
    • 2.下单
    • 3.减少库存
    • 4.支付
  • 总结

业务分析

一般而言,商品秒杀大概可以拆分成以下几步:

用户校验
校验是否多次抢单,保证每个商品每个用户只能秒杀一次

下单
订单信息进入消息队列,等待消费

减少库存
消费订单消息,减少商品库存,增加订单记录

付款
十五分钟内完成支付,修改支付状态

创建表

goods_info 商品库存表

说明
id 主键(uuid)
goods_name 商品名称
goods_stock 商品库存
package com.jason.seckill.order.entity;

/**
 * 商品库存
 */

public class GoodsInfo {

    private String id;
    private String goodsName;
    private String goodsStock;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public String getGoodsStock() {
        return goodsStock;
    }

    public void setGoodsStock(String goodsStock) {
        this.goodsStock = goodsStock;
    }

    @Override
    public String toString() {
        return "GoodsInfo{" +
                "id='" + id + '\'' +
                ", goodsName='" + goodsName + '\'' +
                ", goodsStock='" + goodsStock + '\'' +
                '}';
    }
}

order_info 订单记录表

说明
id 主键(uuid)
user_id 用户id
goods_id 商品id
pay_status 支付状态(0-超时未支付 1-已支付 2-待支付)
package com.jason.seckill.order.entity;

/**
 * 下单记录
 */
public class OrderRecord {

    private String id;
    private String userId;
    private String goodsId;
    /**
     * 0-超时未支付  1-已支付  2-待支付
     */
    private Integer payStatus;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(String goodsId) {
        this.goodsId = goodsId;
    }

    public Integer getPayStatus() {
        return payStatus;
    }

    public void setPayStatus(Integer payStatus) {
        this.payStatus = payStatus;
    }

    @Override
    public String toString() {
        return "OrderRecord{" +
                "id='" + id + '\'' +
                ", userId='" + userId + '\'' +
                ", goodsId='" + goodsId + '\'' +
                '}';
    }
}

功能实现

1.用户校验

使用redis做用户校验,保证每个用户每个商品只能抢一次,上代码:

public boolean checkSeckillUser(OrderRequest order) {
        String key = env.getProperty("seckill.redis.key.prefix") + order.getUserId() + order.getGoodsId();
        return redisTemplate.opsForValue().setIfAbsent(key,"1");
    }

userId+orderId的组合作为key,利用redis的setnx分布式锁原理来实现。如果是限时秒杀,可以通过设置key的过期时间来实现。

2.下单

下单信息肯定是要先扔到消息队列里的,这里采用RabbitMQ来做消息队列,先来看一下消息队列的模型图:

rabbitmq的配置:

#rabbitmq配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#消费者数量
spring.rabbitmq.listener.simple.concurrency=5
#最大消费者数量
spring.rabbitmq.listener.simple.max-concurrency=10
#消费者每次从队列获取的消息数量。写多了,如果长时间得不到消费,数据就一直得不到处理
spring.rabbitmq.listener.simple.prefetch=1
#消费接收确认机制-手动确认
spring.rabbitmq.listener.simple.acknowledge-mode=manual

mq.env=local
#订单处理队列
#交换机名称
order.mq.exchange.name=${mq.env}:order:mq:exchange
#队列名称
order.mq.queue.name=${mq.env}:order:mq:queue
#routingkey
order.mq.routing.key=${mq.env}:order:mq:routing:key

rabbitmq配置类OrderRabbitmqConfig:

/**
 * rabbitmq配置
 */
@Configuration
public class OrderRabbitmqConfig {

    private static final Logger logger = LoggerFactory.getLogger(OrderRabbitmqConfig.class);

    @Autowired
    private Environment env;

    /**
     * channel链接工厂
     */
    @Autowired
    private CachingConnectionFactory connectionFactory;

    /**
     * 监听器容器配置
     */
    @Autowired
    private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;

    /**
     * 声明rabbittemplate
     * @return
     */
    @Bean
    public RabbitTemplate rabbitTemplate(){
        //消息发送成功确认,对应application.properties中的spring.rabbitmq.publisher-confirms=true
        connectionFactory.setPublisherConfirms(true);
        //消息发送失败确认,对应application.properties中的spring.rabbitmq.publisher-returns=true
        connectionFactory.setPublisherReturns(true);
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        //设置消息发送格式为json
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.setMandatory(true);
        //消息发送到exchange回调 需设置:spring.rabbitmq.publisher-confirms=true
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                logger.info("消息发送成功:correlationData({}),ack({}),cause({})",correlationData,ack,cause);
            }
        });
        //消息从exchange发送到queue失败回调  需设置:spring.rabbitmq.publisher-returns=true
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                logger.info("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}",exchange,routingKey,replyCode,replyText,message);
            }
        });
        return rabbitTemplate;
    }

    //---------------------------------------订单队列------------------------------------------------------

    /**
     * 声明订单队列的交换机
     * @return
     */
    @Bean("orderTopicExchange")
    public TopicExchange orderTopicExchange(){
        //设置为持久化 不自动删除
        return new TopicExchange(env.getProperty("order.mq.exchange.name"),true,false);
    }

    /**
     * 声明订单队列
     * @return
     */
    @Bean("orderQueue")
    public Queue orderQueue(){
        return new Queue(env.getProperty("order.mq.queue.name"),true);
    }

    /**
     * 将队列绑定到交换机
     * @return
     */
    @Bean
    public Binding simpleBinding(){
        return BindingBuilder.bind(orderQueue()).to(orderTopicExchange()).with(env.getProperty("order.mq.routing.key"));
    }

    /**
     * 注入订单对列消费监听器
     */
    @Autowired
    private OrderListener orderListener;

    /**
     * 声明订单队列监听器配置容器
     * @return
     */
    @Bean("orderListenerContainer")
    public SimpleMessageListenerContainer orderListenerContainer(){
        //创建监听器容器工厂
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        //将配置信息和链接信息赋给容器工厂
        factoryConfigurer.configure(factory,connectionFactory);
        //容器工厂创建监听器容器
        SimpleMessageListenerContainer container = factory.createListenerContainer();
        //指定监听器
        container.setMessageListener(orderListener);
        //指定监听器监听的队列
        container.setQueues(orderQueue());
        return container;
    }
}

配置类声明了订单队列,交换机,通过指定的routingkey绑定了队列与交换机。另外,rabbitTemplate用来发送消息,ListenerContainer指定监听器(消费者)监听的队列。

客户下单,生产消息,上代码:

@Service
public class SeckillService {

    private static final Logger logger = LoggerFactory.getLogger(SeckillService.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private Environment env;

    /**
     * 生产消息
     * @param order
     */
    public void seckill(OrderRequest order){
        //设置交换机
        rabbitTemplate.setExchange(env.getProperty("order.mq.exchange.name"));
        //设置routingkey
        rabbitTemplate.setRoutingKey(env.getProperty("order.mq.routing.key"));
        //创建消息体
        Message msg = MessageBuilder.withBody(JSON.toJSONString(order).getBytes()).build();
        //发送消息
        rabbitTemplate.convertAndSend(msg);
    }
}

很简单,操作rabbitTemplate,指定交换机和routingkey,发送消息到绑定的队列,等待消费处理。

3.减少库存

消费者消费订单消息,做业务处理。
看一下监听器(消费者)OrderListener:

/**
 * 消息监听器(消费者)
 */
@Component
public class OrderListener implements ChannelAwareMessageListener {

    private static final Logger logger = LoggerFactory.getLogger(OrderListener.class);

    @Autowired
    private OrderService orderService;
    /**
     * 处理接收到的消息
     * @param message 消息体
     * @param channel 通道,确认消费用
     * @throws Exception
     */
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        try{
            //获取交付tag
            long tag = message.getMessageProperties().getDeliveryTag();
            String str = new String(message.getBody(),"utf-8");
            logger.info("接收到的消息:{}",str);
            JSONObject obj = JSONObject.parseObject(str);
            //下单,操作数据库
            orderService.order(obj.getString("userId"),obj.getString("goodsId"));
            //确认消费
            channel.basicAck(tag,true);
        }catch(Exception e){
            logger.error("消息监听确认机制发生异常:",e.fillInStackTrace());
        }
    }
}

业务处理 OrderService:

@Service
public class OrderService {

    @Resource
    private SeckillMapper seckillMapper;

    /**
     * 下单,操作数据库
     * @param userId
     * @param goodsId
     */
    @Transactional()
    public void order(String userId,String goodsId){
        //该商品库存-1(当库存>0时)
        int count = seckillMapper.reduceGoodsStockById(goodsId);
        //更新成功,表明抢单成功,插入下单记录,支付状态设为2-待支付
        if(count > 0){
            OrderRecord orderRecord = new OrderRecord();
            orderRecord.setId(CommonUtils.createUUID());
            orderRecord.setGoodsId(goodsId);
            orderRecord.setUserId(userId);
            orderRecord.setPayStatus(2);
            seckillMapper.insertOrderRecord(orderRecord);
        }
    }
}

Dao接口和Mybatis文件就不往出贴了,这里的逻辑是,update goods_info set goods_stock = goods_stock-1 where goods_stock > 0 and id=#{goodsId},这条update相当于将查询库存和减少库存合并为一个原子操作,避免高并发问题,执行成功,插入订单记录,执行失败,则库存不够抢单失败。

4.支付

订单处理完成后,如果库存减少,也就是抢单成功,那么需要用户在十五分钟内完成支付,这块就要用到死信队列(延迟队列)来处理了,先看模型图:

DLX:dead-letter Exchange 死信交换机
DLK:dead-letter RoutingKey 死信路由
ttl:time-to-live 超时时间
死信队列中,消息到期后,会通过DLX和DLK进入到pay-queue,进行消费。这是另一组消息队列,和订单消息队列是分开的。这里注意他们的绑定关系,主交换机绑定死信队列,死信交换机绑定的是主队列(pay queue)。
接下来声明图中的一系列组件,首先application.properties中增加配置:

#支付处理队列
#主交换机
pay.mq.exchange.name=${mq.env}:pay:mq:exchange
#死信交换机(DLX)
pay.dead-letter.mq.exchange.name=${mq.env}:pay:dead-letter:mq:exchange
#主队列
pay.mq.queue.name=${mq.env}:pay:mq:queue
#死信队列
pay.dead-letter.mq.queue.name=${mq.env}:pay:dead-letter:mq:queue
#主routingkey
pay.mq.routing.key=${mq.env}:pay:mq:routing:key
#死信routingkey(DLK)
pay.dead-letter.mq.routing.key=${mq.env}:pay:dead-letter:mq:routing:key
#支付超时时间(毫秒)(TTL),测试原因,这里模拟5秒,如果是生产环境,这里可以是15分钟等
pay.mq.ttl=5000

配置类OrderRabbitmqConfig中增加支付队列和死信队列的声明:

    /**
     * 死信队列,十五分钟超时
     * @return
     */
    @Bean
    public Queue payDeadLetterQueue(){
        Map args = new HashMap();
        //声明死信交换机
        args.put("x-dead-letter-exchange",env.getProperty("pay.dead-letter.mq.exchange.name"));
        //声明死信routingkey
        args.put("x-dead-letter-routing-key",env.getProperty("pay.dead-letter.mq.routing.key"));
        //声明死信队列中的消息过期时间
        args.put("x-message-ttl",env.getProperty("pay.mq.ttl",int.class));
        //创建死信队列
        return new Queue(env.getProperty("pay.dead-letter.mq.queue.name"),true,false,false,args);
    }

    /**
     * 支付队列交换机(主交换机)
     * @return
     */
    @Bean
    public TopicExchange payTopicExchange(){
        return new TopicExchange(env.getProperty("pay.mq.exchange.name"),true,false);
    }

    /**
     * 将主交换机绑定到死信队列
     * @return
     */
    @Bean
    public Binding payBinding(){
        return BindingBuilder.bind(payDeadLetterQueue()).to(payTopicExchange()).with(env.getProperty("pay.mq.routing.key"));
    }

    /**
     * 支付队列(主队列)
     * @return
     */
    @Bean
    public Queue payQueue(){
        return new Queue(env.getProperty("pay.mq.queue.name"),true);
    }

    /**
     * 死信交换机
     * @return
     */
    @Bean
    public TopicExchange payDeadLetterExchange(){
        return new TopicExchange(env.getProperty("pay.dead-letter.mq.exchange.name"),true,false);
    }

    /**
     * 将主队列绑定到死信交换机
     * @return
     */
    @Bean
    public Binding payDeadLetterBinding(){
        return BindingBuilder.bind(payQueue()).to(payDeadLetterExchange()).with(env.getProperty("pay.dead-letter.mq.routing.key"));
    }

    /**
     * 注入支付监听器
     */
    @Autowired
    private PayListener payListener;

    /**
     * 支付队列监听器容器
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer payMessageListenerContainer(){
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factoryConfigurer.configure(factory,connectionFactory);
        SimpleMessageListenerContainer listenerContainer = factory.createListenerContainer();
        listenerContainer.setMessageListener(payListener);
        listenerContainer.setQueues(payQueue());
        return listenerContainer;
    }

支付队列和死信队列的Queue、Exchange、routingkey都已就绪。
看生产者:

@Service
public class OrderService {

    @Resource
    private SeckillMapper seckillMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private Environment env;

    /**
     * 下单,操作数据库
     * @param userId
     * @param goodsId
     */
    @Transactional()
    public void order(String userId,String goodsId){
        //该商品库存-1(当库存>0时)
        int count = seckillMapper.reduceGoodsStockById(goodsId);
        //更新成功,表明抢单成功,插入下单记录,支付状态设为2-待支付
        if(count > 0){
            OrderRecord orderRecord = new OrderRecord();
            orderRecord.setId(CommonUtils.createUUID());
            orderRecord.setGoodsId(goodsId);
            orderRecord.setUserId(userId);
            orderRecord.setPayStatus(2);
            seckillMapper.insertOrderRecord(orderRecord);
            //将该订单添加到支付队列
            rabbitTemplate.setExchange(env.getProperty("pay.mq.exchange.name"));
            rabbitTemplate.setRoutingKey(env.getProperty("pay.mq.routing.key"));
            rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
            String json = JSON.toJSONString(orderRecord);
            Message msg = MessageBuilder.withBody(json.getBytes()).build();
            rabbitTemplate.convertAndSend(msg);
        }
    }
}

在OrderService中,数据库操作完成后,将订单信息发送到死信队列,死信队列中的消息会在十五分钟后进入到支付队列,等待消费。
再看消费者:

@Component
public class PayListener implements ChannelAwareMessageListener {

    private static final Logger logger = LoggerFactory.getLogger(PayListener.class);

    @Autowired
    private PayService payService;

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        Long tag = message.getMessageProperties().getDeliveryTag();
        try {
            String str = new String(message.getBody(), "utf-8");
            logger.info("接收到的消息:{}",str);
            JSONObject json = JSON.parseObject(str);
            String orderId = json.getString("id");
            //确认是否付款
            payService.confirmPay(orderId);
            //确认消费
            channel.basicAck(tag, true);
        }catch(Exception e){
            logger.info("支付消息消费出错:{}",e.getMessage());
            logger.info("出错的tag:{}",tag);
        }
    }
}

PayService:

@Service
public class PayService {

    private static final Logger logger = LoggerFactory.getLogger(PayService.class);

    @Resource
    private SeckillMapper seckillMapper;

    /**
     * 确认是否支付
     * @param orderId
     */
    public void confirmPay(String orderId){
        OrderRecord orderRecord = seckillMapper.selectNoPayOrderById(orderId);
        //根据订单号校验该用户是否已支付
        if(checkPay(orderId)){
            //已支付
            orderRecord.setPayStatus(1);
            seckillMapper.updatePayStatus(orderRecord);
            logger.info("用户{}已支付",orderId);
        }else{
            //未支付
            orderRecord.setPayStatus(0);
            seckillMapper.updatePayStatus(orderRecord);
            //取消支付后,商品库存+1
            seckillMapper.returnStock(orderRecord.getGoodsId());
            logger.info("用户{}未支付",orderId);
        }
    }

    /**
     * 模拟判断订单支付成功或失败,成功失败随机
     * @param orderId
     * @return
     */
    public boolean checkPay(String orderId){
        Random random = new Random();
        int res = random.nextInt(2);
        return res==0?false:true;
    }

这里checkPay()方法模拟调用第三方支付接口来判断用户是否已支付。若支付成功,订单改为已支付状态,支付失败,改为已取消状态,库存退回。

总结

整个demo,是两组消息队列撑起来的,一组订单消息队列,一组支付消息队列,而每一组队列都是由queue、exchange、routingkey、生产者以及消费者组成。交换机通过routingkey绑定队列,rabbitTemplate通过指定交换机和routingkey将消息发送到指定队列,消费者监听该队列进行消费。不同的是第二组支付队列里嵌入了死信队列来做一个十五分钟的延迟支付。

到此这篇关于SpringBoot+RabbitMQ+Redis实现商品秒杀的文章就介绍到这了,更多相关SpringBoot+RabbitMQ+Redis实现商品秒杀内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解决RabbitMq消息队列Qos Prefetch消息堵塞问题

    mq是实现代码扩展的有利手段,个人喜欢用概念来学习新知识,介绍堵塞问题的之前,先来段概念的学习. ConnectionFactory:创建connection的工厂类 Connection: 简单理解为socket Channel:和mq交互的接口,定义queue.exchange和绑定queue.exhange等接口都是它. 接下来就是和mq的交互类 exchange:简单地看成路由,类型不是重点,看看官网即可 queue:客户端监听的是queue,而不是exchange,但是使用queue的

  • SpringBoot整合RabbitMQ消息队列的完整步骤

    SpringBoot整合RabbitMQ 主要实现RabbitMQ以下三种消息队列: 简单消息队列(演示direct模式) 基于RabbitMQ特性的延时消息队列 基于RabbitMQ相关插件的延时消息队列 公共资源 1. 引入pom依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId>

  • springboot2.0集成rabbitmq的示例代码

    安装rabbitmq 简介: rabbitmq即一个消息队列,主要用来实现应用程序的异步和解耦,消息缓冲,消息分发的作用. 由于rabbitmq依赖于erlang语言,所以先安装erlang: 添加erlang solutions源 $ wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm $ sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm $ su

  • RabbitMQ 如何解决消息幂等性的问题

    前言 关于MQ消费者的幂等性问题,在于MQ的重试机制,因为网络原因或客户端延迟消费导致重复消费.使用MQ重试机制需要注意的事项以及如何解决消费者幂等性问题以下将逐一讲解. 1. RabbitMQ自动重试机制 消费者在消费消息的时候,如果消费者业务逻辑出现程序异常,这个时候我们如何处理? 使用重试机制,RabbitMQ默认开启重试机制. 实现原理: @RabbitHandler注解 底层使用Aop拦截,如果程序(消费者)没有抛出异常,自动提交事务 如果Aop使用异常通知拦截获取到异常后,自动实现补

  • rabbitmq(中间消息代理)在python中的使用详解

    在之前的有关线程,进程的博客中,我们介绍了它们各自在同一个程序中的通信方法.但是不同程序,甚至不同编程语言所写的应用软件之间的通信,以前所介绍的线程.进程队列便不再适用了:此种情况便只能使用socket编程了,然而不同程序之间的通信便不再像线程进程之间的那么简单了,要考虑多种情况(比如其中一方断线另一方如何处理:消息群发,多个程序之间的通信等等),如果每遇到一次程序间的通信,便要根据不同情况编写不同的socket,还要维护.完善这个socket这会使得编程人员的工作量大大增加,也使得程序更易崩溃

  • Java编程rabbitMQ实现消息的收发

    java实现rAMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然. AMQP的主要特征是面向消息.队列.路由(包括点对点和发布/订阅).可靠性.安全. RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.Actio

  • SpringBoot+RabbitMQ+Redis实现商品秒杀的示例代码

    目录 业务分析 创建表 功能实现 1.用户校验 2.下单 3.减少库存 4.支付 总结 业务分析 一般而言,商品秒杀大概可以拆分成以下几步: 用户校验 校验是否多次抢单,保证每个商品每个用户只能秒杀一次 下单 订单信息进入消息队列,等待消费 减少库存 消费订单消息,减少商品库存,增加订单记录 付款 十五分钟内完成支付,修改支付状态 创建表 goods_info 商品库存表 列 说明 id 主键(uuid) goods_name 商品名称 goods_stock 商品库存 package com.

  • SpringBoot集成redis实现分布式锁的示例代码

    1.准备 使用redis实现分布式锁,需要用的setnx(),所以需要集成Jedis 需要引入jar,jar最好和redis的jar版本对应上,不然会出现版本冲突,使用的时候会报异常redis.clients.jedis.Jedis.set(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String; 我使用的redis版本是2.3.0,Jedis使用的是3.3.0 <de

  • SpringBoot整合Redis实现访问量统计的示例代码

    目录 前言 Spring Boot 整合 Redis 引入依赖.增加配置 翠花!上代码 前言 之前开发系统的时候客户提到了一个需求:需要统计某些页面的访问量,记得当时还纠结了一阵子,不知道怎么去实现这个功能,后来还是在大佬的带领下借助 Redis 实现了这个功能.今天又回想起了这件事,正好和大家分享一下 Spring Boot 整合 Redis 实现访问量统计的全过程. 首先先解释一下为什么需要借助 Redis,其实原因也很简单,就是因为它非常快(每秒可执行大约110000次的 SET 操作,每

  • SpringBoot结合Redis实现接口幂等性的示例代码

    目录 介绍 实现过程 引入 maven 依赖 spring 配置文件写入 引入 Redis 自定义注解 token 的创建和实现 拦截器的配置 测试用例 介绍 幂等性的概念是,任意多次执行所产生的影响都与一次执行产生的影响相同,按照这个含义,最终的解释是对数据库的影响只能是一次性的,不能重复处理.手段如下 数据库建立唯一索引 token机制 悲观锁或者是乐观锁 先查询后判断 小小主要带你们介绍Redis实现自动幂等性.其原理如下图所示. 实现过程 引入 maven 依赖 <dependency>

  • springboot +rabbitmq+redis实现秒杀示例

    目录 实现说明 1.工具准备 2.数据表 3.pom 4.代码结构 5.配置config 6.订单业务层 7.redis实现层 8.mq实现层 9.redis模拟初始化库存量 10.controller控制层 11.测试 12.测试结果 实现说明 这里的核心在于如何在大并发的情况下保证数据库能扛得住压力,因为大并发的瓶颈在于数据库.如果用户的请求直接从前端传到数据库,显然,数据库是无法承受几十万上百万甚至上千万的并发量的.因此,我们能做的只能是减少对数据库的访问.例如,前端发出了100万个请求,

  • springboot集成redis实现简单秒杀系统

    本文实例为大家分享了springboot集成redis实现简单秒杀系统的具体代码,供大家参考,具体内容如下 项目是有地址的,我会放到文章的最后面 1. 直接service,我们会介绍两种秒杀模式 public interface GoodsService { /** * 通过lua脚本实现的秒杀 * @param skuCode 商品编码 * @param buyNum 购买数量 * @return 购买数量 */ Long flashSellByLuaScript(String skuCode

  • Docker 部署 SpringBoot 项目整合 Redis 镜像做访问计数示例代码

    最终效果如下 大概就几个步骤 1.安装 Docker CE 2.运行 Redis 镜像 3.Java 环境准备 4.项目准备 5.编写 Dockerfile 6.发布项目 7.测试服务 环境准备 系统:Ubuntu 17.04 x64 Docker 17.12.0-ce IP:45.32.31.101 一.安装 Docker CE 国内不建议使用:"脚本进行安装",会下载安装很慢,使用步骤 1 安装,看下面的链接:常规安装方式 1.常规安装方式 Ubuntu 17.04 x64 安装

  • SpringBoot结合Redis哨兵模式的实现示例

    Redis哨兵模式 Redis Sentinel介绍 Redis Sentinel是Redis高可用的实现方案.Sentinel是一个管理多个Redis实例的工具,它可以实现对Redis的监控.通知.自动故障转移. Redis Sentinel主要功能 Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常. 提醒(Notificatio

  • SpringBoot+RabbitMQ方式收发消息的实现示例

    本篇会和SpringBoot做整合,采用自动配置的方式进行开发,我们只需要声明RabbitMQ地址就可以了,关于各种创建连接关闭连接的事都由Spring帮我们了~ 交给Spring帮我们管理连接可以让我们专注于业务逻辑,就像声明式事务一样易用,方便又高效. 祝有好收获,先赞后看,快乐无限. 本文代码:   https://gitee.com/he-erduo/spring-boot-learning-demo https://github.com/he-erduo/spring-boot-lea

  • Thinkphp5+Redis实现商品秒杀代码实例讲解

    环境:wamp,redis 要求:安装WAMP,Redis,以及为PHP安装Redis扩展 秒杀功能大致思路:获取缓存列表的长度,如果长度(llen)等于0,就停止秒杀,即秒杀失败,如果长度大于0,则继续运行,先从缓存中移除一个元素(lpop),再进行数据库操作(添加订单表,商品库存数量减一),如果再进一个人秒杀,就再走一遍流程,循环往复. 一.安装Redis扩展 1.查看PHP版本信息 打开phpinfo.php,查看PHP版本,我的是PHP7.3.4,还有一个需要注意Architecture

随机推荐