美文网首页
秒杀场景设计 一

秒杀场景设计 一

作者: rainbowz | 来源:发表于2020-11-04 15:20 被阅读0次

1数据库设计
用户表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

2库存表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for stock
-- ----------------------------
DROP TABLE IF EXISTS `stock`;
CREATE TABLE `stock`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '名称',
  `count` int(11) NOT NULL COMMENT '库存',
  `sale` int(11) NOT NULL COMMENT '已售',
  `version` int(11) NOT NULL COMMENT '乐观锁,版本号',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

3订单表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for stock_order
-- ----------------------------
DROP TABLE IF EXISTS `stock_order`;
CREATE TABLE `stock_order`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `sid` int(11) NOT NULL COMMENT '库存ID',
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '商品名称',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

1.秒杀商品写入缓存

 /**
     * 秒杀商品库存缓存写入Reids
     */
    @Test
    public void testLoads() {
        Stock stock = stockDao.selectStock(1);
        redisTemplate.opsForValue().set("kill" + stock.getId(), stock.getId() + "");
    }

2.乐观锁

/**
     * 乐观锁
     */
    @Test
    public void testOptimismLock() {
        Stock stock1 = stockDao.selectStock(1);
        Stock stock2 = stockDao.selectStock(1);
        stockDao.updateSale(stock1);
        int res = stockDao.updateSale(stock2);
        if (res == 0) {
            System.out.println("更新失败");
        }
    }

3.查询缓存

/**
     * 查询缓存
     * 缓存命中,返回缓存;缓存未命中 查询数据库;更新缓存
     */
    @Test
    public void updateCacheCount() {
        int stockId = 1;
        String countKey = stringRedisTemplate.opsForValue().get(CacheKey.STOCK_COUNT + "_" + stockId);
        if (countKey != null) {
            //缓存命中
            System.out.println(countKey);
        } else {
            Stream<Integer> integerStream = Stream.of(stockDao.selectStock(stockId)).map(e -> {
                return e.getCount() - e.getSale();
            });
            Integer integer = integerStream.findFirst().get();
            Integer count = stockDao.selectStock(1).getCount();
            stringRedisTemplate.opsForValue().set(CacheKey.STOCK_COUNT + "_" + stockId, integer + "", 3600, TimeUnit.SECONDS);
        }
    }

4.用户验证的verifyCode

/**
     * 生成验证Code
     */
    @Test
    public void saveVerifyCode() {
        int stockId = 1;
        int userId = 1;
        String code = stringRedisTemplate.opsForValue().get(CacheKey.HASH_KEY + "_" + stockId);
        User user = userDao.selectByPrimaryKey(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        if (code == null) {
            // 生成hash
            String verify = SALT + stockId + userId + "";
            String verifyHash = DigestUtils.md5DigestAsHex(verify.getBytes());
            stringRedisTemplate.opsForValue().set(CacheKey.HASH_KEY + "_" + stockId, verifyHash, 3600, TimeUnit.SECONDS);
        } else {

            System.out.println(code);
        }
    }
  1. 综合
    code-snapshot.png

参考:

Mysql和Redis双写一致性

-先删除缓存,再更新数据库

-先更新数据库,再删缓存

-先删除缓存,再更新数据库,缓存延时双删

接口限流
超卖

-令牌桶限流:使用Guava的RateLimiter实现令牌桶限流接口
-乐观锁

参考:
https://github.com/zitai98/ms

相关文章

  • 秒杀场景设计 一

    1数据库设计用户表 2库存表 3订单表 1.秒杀商品写入缓存 2.乐观锁 3.查询缓存 4.用户验证的verify...

  • 彻底弄懂 “秒杀系统”

    今天我们一起来看看,一套秒杀系统在架构设计上需要有哪些考量: 秒杀场景的特点 系统隔离的设计思路 客户端设计 代理...

  • JavaWeb秒杀业务场景设计

    秒杀业务场景设计问题经常被面试的时候被问到,在实际业务中,也常常需要实现,下面我们来看看如何实现秒杀业务. 秒杀业...

  • 秒杀系统的设计

    秒杀这个业务场景是我们生活中比较常见的,这次就来总结一下秒杀系统设计的要点 使用Redis进行不同级别的缓存 因为...

  • 高并发下的下单功能设计

    功能需求:设计一个秒杀系统 初始方案 商品表设计:热销商品提供给用户秒杀,有初始库存。 秒杀订单表设计:记录秒杀成...

  • 架构成长之路:高并发下的下单功能设计

    功能需求:设计一个秒杀系统 初始方案 商品表设计:热销商品提供给用户秒杀,有初始库存。 秒杀订单表设计:记录秒杀成...

  • 面试实战考核:设计一个高并发下的下单功能

    功能需求:设计一个秒杀系统 初始方案 商品表设计:热销商品提供给用户秒杀,有初始库存。 秒杀订单表设计:记录秒杀成...

  • 【Java 实战】通过Redis 和 MQ 简单实现秒杀功能

    项目场景 实现一个商品秒杀的功能,能后台自定义秒杀时间段、商品库存等信息。 一、设计思路 这里简单分享下思路: 1...

  • 秒杀系统架构分析、设计、原理书目录

    秒杀系统架构分析、设计、原理 秒杀业务分析 秒杀技术挑战 秒杀架构原则 秒杀架构设计 大并发带来的挑战 作弊的手段...

  • 秒杀场景如何设计呢?

    1 秒杀场景 秒杀场景 登陆12306进行火车票抢座 1599元购入飞天茅台 周董演唱会的门票 双十一秒杀活动 秒...

网友评论

      本文标题:秒杀场景设计 一

      本文链接:https://www.haomeiwen.com/subject/qasgvktx.html