Disruptor并发<二> _ 秒杀示例

本文详细介绍了如何使用Spring Boot和Disruptor实现秒杀系统的各个组件,包括代码示例中的表结构设计、用户下单、本地处理队列、事件对象、消费者处理(如订单创建、库存扣减、消息发送和异常捕获)以及Disruptor的创建和配置。通过这个过程,读者可以学习到并发处理和消息队列在高并发场景中的应用。

目录

一、秒杀流程

二、代码示例

1. 依赖及表结构

2. 秒杀下单

3. 本地处理队列

4. 事件对象

5. 消费者 

6. 异常处理消费者

7. 事件生产者

8. 创建Disruptor

三、参考资料


一、秒杀流程

二、代码示例

1. 依赖及表结构

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.4.4</version>
</dependency>
// 商品库存表
CREATE TABLE `t_goods_stock`  (
  `id` bigint(4) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `goods_id` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品ID',
  `stock` bigint(255) NULL DEFAULT NULL COMMENT '库存',
  `price` decimal(8, 2) NULL DEFAULT NULL COMMENT '单价',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;


// 订单表
CREATE TABLE `t_order`  (
  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户ID',
  `goods_id` bigint(20) NULL DEFAULT NULL COMMENT '商品ID',
  `number` int(11) NULL DEFAULT NULL COMMENT '购买数量',
  `price` decimal(8, 2) NULL DEFAULT NULL COMMENT '单价',
  `total` decimal(8, 2) NULL DEFAULT NULL COMMENT '总价',
  `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 61686 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2. 秒杀下单

a. Contoller层

package com.common.instance.test.controller;

import com.common.instance.test.core.Response;
import com.common.instance.test.service.SeckillService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Random;

/**
 * @description 秒杀活动
 * @author tcm
 * @version 1.0.0
 * @date 2021/12/23 15:47
 **/
@RestController
@RequestMapping("/seckill")
@Api(tags = "秒杀活动")
public class SeckillController {

    @Resource
    private SeckillService seckillService;

    @GetMapping("/isSeckillGoods")
    @ApiOperation("用户是否抢到商品")
    public Response<Boolean> isSeckillGoods(String goodsId){
        // 返回结果
        Boolean isSeckill = false;
        try {
            // 用户是否抢到商品
            // 随机用户
            String userId = String.valueOf(System.currentTimeMillis());
            // 随机商品数量
            Random rand = new Random();
            Integer num = rand.nextInt(10) + 1;

            isSeckill = seckillService.isSeckillGoods(userId, goodsId, num);
        } catch (Exception e) {
            e.printStackTrace();
            return Response.error();
        }
        return Response.success(isSeckill);
    }

}

b. Service层

package com.common.instance.test.service.impl;

import com.common.instance.test.dao.TGoodsStockDao;
import com.common.instance.test.disruptor.event.SeckillGoodsEvent;
import com.common.instance.test.disruptor.localQueue.RedisQueue;
import com.common.instance.test.entity.TGoodsStock;
import com.common.instance.test.service.SeckillService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description 秒杀活动
 * @author tcm
 * @version 1.0.0
 * @date 2021/12/23 15:49
 **/
@Service
public class SeckillServiceImpl implements SeckillService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private TGoodsStockDao tGoodsStockDao;

    @Override
    public Boolean isSeckillGoods(String userId, String goodsId, Integer num) {
        // 返回结果
        Boolean result = false;

        // 商品秒杀数量
        Long count = redisTemplate.opsForValue().decrement(RedisQueue.SECKILL_KEY + goodsId, num);
        // 查询商品库存,设置值
        if (Objects.nonNull(count) && count < 0 ) {
            TGoodsStock goodsStock = tGoodsStockDao.selectByPrimaryKey(1L);
            if (Objects.nonNull(goodsStock)) {
                count = goodsStock.getStock() - num;
                redisTemplate.opsForValue().set(RedisQueue.SECKILL_KEY + goodsId, count, 1, TimeUnit.DAYS);
            }
        }
        if (Objects.nonNull(count) && count >= 0) {
            // 创建秒杀商品对象事件
            SeckillGoodsEvent seckillG
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值