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

秒杀场景设计 一

作者: 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

    相关文章

      网友评论

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

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