java 2023秒杀项目 day(1) 面经

news2024/11/15 12:26:11

java 2023杀项目 day(1) 面经

  • 一、秒杀项目
    • 1.1 如何设计秒杀系统
    • 1.2 数据库
  • 二、业务
    • 2.1 登录
      • 2.2.1 密码加密
    • 2.2.2 密码参数校验
      • 2.2.3 分布式session
        • 2.2.3.1 解决方案
      • 2.2.4 参数解析器
    • 2.3 异常处理
      • 2.3.1 ControllerAdvicer+ExceptionHandler
    • 2.4 秒杀
      • 2.4.1 逻辑
      • 2.4.1 秒杀前判断
      • 2.4.2 进行秒杀
  • 三、问题
    • 3.1 前端不能传秒杀库存
    • 3.2 问什么新建秒杀表不在原表加字段
    • 3.3 打包
  • 四、压测
    • 4.1 测试商品详情接口
      • 1.4.1 查询文件列表
    • 4.2 单服务秒杀测试
      • 4.2.1 原始秒杀测试没有任何优化策略
      • 4.2.2 使用了mq后的测试
    • 4.3 多服务秒杀测试
  • 五、秒杀优化
    • 5.1 页面优化
      • 5.1.1 页面缓存(返回的是整个html,前后端未分离)
      • 5.1.2 url缓存
      • 5.1.3 页面静态化(前后端分离)
    • 5.2 单服务秒杀后端优化
      • 5.2.1 减库存优化及修正
      • 5.2.2 用户重复秒杀问题
      • 5.2.3 使用redis优化
      • 5.2.4 mq秒杀信息的获取
  • 六、技术作用
    • 6.1 redis
    • 6.2 ThreadLocal
    • 6.3 Rabbitmq
  • 七、安全优化
    • 7.1 隐藏接口地址
    • 7.2 验证码
    • 7.3 接口限流
      • 7.3.1 限流标准
      • 7.3.2 通用限流

一、秒杀项目

1.1 如何设计秒杀系统

  • 高可用
  • 高性能:支持高并发访问
  • 一致性:秒杀要保持数据的一致性

1.2 数据库

  • 字符集:utf8mb4
    可以存储emoji表情

二、业务

2.1 登录

2.2.1 密码加密

  • MD5(MD5(密码+固定salt)+随机salt)
  • 前端使用固定salt进行第一次加密,后端使用随机salt进行第二次加密。

2.2.2 密码参数校验

  • pom
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
  • 自定注解
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {
            IsMobileValidator.class
        }
)
public @interface IsMobile {
    //该字段必填

    boolean required() default true;

    String message() default "手机号码格式错误";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

package com.example.seckilldemo.validator;

import com.example.seckilldemo.utils.ValidatorUtil;
import org.thymeleaf.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 手机号码校验规则
 *
 * @author: LC
 * @date 2022/3/2 3:08 下午
 * @ClassName: IsMobileValidator
 */
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {

    private boolean required = false;

    @Override
    public void initialize(IsMobile constraintAnnotation) {
//        ConstraintValidator.super.initialize(constraintAnnotation);
        required = constraintAnnotation.required();
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (required) {
            return ValidatorUtil.isMobile(s);
        } else {
            if (StringUtils.isEmpty(s)) {
                return true;
            } else {
                return ValidatorUtil.isMobile(s);
            }
        }
    }
}

2.2.3 分布式session

  • 请求通过分布器分发到不同的tomcat服务器,有的tomcat存储了用户相关的session信息,有的没有,当请求分发到没有session信息的tomcat服务器上时,用户需要重新进行登录。

2.2.3.1 解决方案

  • session复制:会增加存储,只需要进行tomcat配置
  • 后端集中存储,会增加复杂度

2.2.4 参数解析器

  • 配置
package com.example.seckilldemo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * MVC配置类
 *
 * @author: LC
 * @date 2022/3/3 2:37 下午
 * @ClassName: WebConfig
 */
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private UserArgumentResolver userArgumentResolver;
    @Autowired
    private AccessLimitInterceptor accessLimitInterceptor;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
//        WebMvcConfigurer.super.addArgumentResolvers(resolvers);
        resolvers.add(userArgumentResolver);
    }

    //静态资源展示
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        //swagger 和 knife4j
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(accessLimitInterceptor);
    }
}

  • 参数解析实现
package com.example.seckilldemo.config;

import com.example.seckilldemo.entity.TUser;
import com.example.seckilldemo.service.ITUserService;
import com.example.seckilldemo.utils.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义用户参数
 *
 * @author: LC
 * @date 2022/3/3 4:46 下午
 * @ClassName: UserArgumentResolver
 */
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private ITUserService itUserService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Class<?> parameterType = parameter.getParameterType();
        return parameterType == TUser.class;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        return UserContext.getUser();

        //        HttpServletRequest nativeRequest = webRequest.getNativeRequest(HttpServletRequest.class);
//        HttpServletResponse nativeResponse = webRequest.getNativeResponse(HttpServletResponse.class);
//        String userTicket = CookieUtil.getCookieValue(nativeRequest, "userTicket");
//        if (StringUtils.isEmpty(userTicket)) {
//            return null;
//        }
//        return itUserService.getUserByCookie(userTicket, nativeRequest, nativeResponse);
    }

}

2.3 异常处理

2.3.1 ControllerAdvicer+ExceptionHandler

处理controller抛出的异常。

2.4 秒杀

2.4.1 逻辑

2.4.1 秒杀前判断

  • 如果在秒杀范围内,前端是会出现秒杀按钮的
  • 判断用户是否登录
  • 判断秒杀商品的库存是否足够
  • 判断用户是否重复下单,查看秒杀订单表
  • 进行秒杀,进行减库存,然后生成秒杀订单表,跳转到订单详情页面

2.4.2 进行秒杀

  • 修改库从需要判断库从大于0才及进行修改:使用update语句
boolean seckillGoodsResult = itSeckillGoodsService.update(new UpdateWrapper<TSeckillGoods>()
                .setSql("stock_count = " + "stock_count-1")
                .eq("goods_id", goodsVo.getId())
                .gt("stock_count", 0)
        );
  • 生成秒杀详情订单

三、问题

3.1 前端不能传秒杀库存

前端传递的数据可能会被修改

3.2 问什么新建秒杀表不在原表加字段

  • 如果秒杀活动较多每次都要在原表上进行修改,比较麻烦,而且物品的原价和秒杀价可能同时使用,在原表修改,容易出错。

3.3 打包

  • 这里需要maven插件
  • 去掉test
    mvn clean
    mvn package
  • java -jar jar包运行
 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

四、压测

4.1 测试商品详情接口

1.4.1 查询文件列表

在这里插入图片描述

4.2 单服务秒杀测试

4.2.1 原始秒杀测试没有任何优化策略

  • jmeter结果
  • 出现超卖的情况
  • 此时没有添加事务,没有在扣库存前判断库存是否大于0
    在这里插入图片描述
    在这里插入图片描述

4.2.2 使用了mq后的测试

在这里插入图片描述

4.3 多服务秒杀测试

五、秒杀优化

5.1 页面优化

5.1.1 页面缓存(返回的是整个html,前后端未分离)

将页面渲染好后缓存到redis中,设置过期时间T,这样用户得到的就是T内的页面。这样在T时间内不用每次都渲染页面,减少了时间。T不能太长,也不能太短。

5.1.2 url缓存

和页面缓存差不多,只不过url会有动态参数,所以缓存的多一点。根据不同动态参数进行缓存。

5.1.3 页面静态化(前后端分离)

后端只需传递数据到前端,此时后端不需要返回整个html页面了。

5.2 单服务秒杀后端优化

5.2.1 减库存优化及修正

  • 加事务
  • 判断库存>0才进行减库存操作
  • 添加唯一索引防止用户重复下单,这个重复下单是防止用户下用户id和商品id相同的单,上面的防止重复下单是防止用户下多个不同的单。

5.2.2 用户重复秒杀问题

  • 重复秒杀有2种,一种对同一商品进行秒杀,一种对

通过建立用户ID和商品ID的唯一索引。

5.2.3 使用redis优化

  • 秒杀前将商品信息都加入到redis中,进行预减库存,同时生成秒杀消息,发送到mq对列,给前端返回信息,前端根据返回的结构展示正在秒杀中页面。
  • 使用内存标记减少对redis的访问,原来是库存不足时还是需要通过访问redis,现在时设置额外的变量先访问变量,当变量种的库存不足直接返回,较少对redis的访问。

5.2.4 mq秒杀信息的获取

  • 数据库查询到秒杀的订单则秒杀成功,返回1
  • 数据库查询不到秒杀的订单且redis中商品的库存小于等于0,则秒杀失败
  • 秒杀正在进行中

六、技术作用

6.1 redis

  • 存储商品库存信息
  • 进行预减库存操作
  • 存储用户秒杀的订单信息,进行重复秒杀判断
  • 辅助验证码验证

6.2 ThreadLocal

  • 每个ThreadLocal都有一个自己的ThreadLocalMap,将数据以key,value的形式存到ThreadLocalMap中。

6.3 Rabbitmq

  • 异步下单

七、安全优化

7.1 隐藏接口地址

7.2 验证码

7.3 接口限流

7.3.1 限流标准

最大qps的70%~80%

7.3.2 通用限流

  • 实现根据用户id对用户进行限流
  • 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {

    int second();

    int maxCount();

    boolean needLogin() default true;
}

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

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

相关文章

图像处理——以支票识别为例

用到环境 1、pycharm community edition 2022.3.2 2、Python 3.10 后续应该会在资源上传项目&#xff0c;需要的话可以私信我。 流程 图1 扩展实验“金额识别”流程图 正文 导入 cv2、pytesseract、re 和 locale 模块。 使用 cv2.imread() 函数加载名为 cheque.jpg 的支票图像…

ROS:结构

目录 前言一、设计者二、维护者三、系统架构四、ROS自身结构 前言 从不同的角度&#xff0c;对ROS架构的描述也是不同的&#xff0c;一般我们可以从设计者、维护者、系统结构与自身结构4个角度来描述ROS结构: 一、设计者 ROS设计者将ROS描述为“ROS Plumbing Tools Capab…

数仓工具Hive 概述

Hive Hive简介Hive架构HiveSQL语法不同之处建表语句查询语句 Hive查看执行计划Hive文件格式 Hive简介 Hive是由Facebook开源&#xff0c;基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。 通过Hive可以将mapred…

数字IC前端学习笔记:仲裁轮询(三)

相关文章 数字IC前端学习笔记&#xff1a;LSFR&#xff08;线性反馈移位寄存器&#xff09; 数字IC前端学习笔记&#xff1a;跨时钟域信号同步 数字IC前端学习笔记&#xff1a;信号同步和边沿检测 数字IC前端学习笔记&#xff1a;锁存器Latch的综合 数字IC前端学习笔记&am…

mitmproxy抓包原理

文章目录 mitmproxy原理详解1 mitmproxy 基本原理2 作为中间代理获取HTTP请求信息2.1 应对显式HTTP请求2.2 应对隐式HTTP请求 3 作为中间代理获取HTTPS请求信息3.1 显式HTTPS请求1) 获取远程主机名2) 处理主题备用名称SAN3) 处理服务器名称指示SNI4) 显式HTTPS请求信息获取整个…

基于深度学习的高精度烟雾检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度烟雾检测识别系统可用于日常生活中或野外来检测与定位烟雾目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的烟雾目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…

为什么数据库字段建议设置为NOT NULL?

目录 一、性能 二、开发的友好性 三、聚合函数不准确 四、null与其它值计算 五、distinct、group by、order by的问题 六、索引问题 七、其它问题 一、性能 如果查询中包含可为null的列&#xff0c;对MYSQL来说更难优化&#xff0c;因为可为null的列使得索引、索引统计…

NUCLEO-F411RE RT-Thread 体验 (9) - GCC环境 PWM的驱动移植以及简单使用

NUCLEO-F411RE RT-Thread 体验 (9) - GCC环境 PWM的驱动移植以及简单使用 驱动移植 驱动位于drv_pwm.c文件中&#xff0c;components层代码位于rt_drv_pwm.c中。 修改Makefile文件 修改配置文件rtconfig.h LED2链接PA5&#xff0c;而TIM2_CHANNEL1可从PA5输出PWM&#xff0…

ubuntu命令

查看当前用户 whoami 进入root权限 sudo su 修改用户名密码 sudo passwd username #修改用户密码 //username是用户设置用户名&#xff0c;记得替换 sudo passwd root #修改root密码 https://blog.csdn.net/m0_54647521/article/details/127521032 重启…

图形编辑器开发:以光标位置缩放画布

大家好&#xff0c;我是前端西瓜哥。 画布缩放是图形设计工具中很重要的基础能力。 通过它&#xff0c;我们可以像举着一台摄影机&#xff0c;在图形所在的世界到处游逛&#xff0c;透过镜头&#xff0c;可以只看自己想看的图形&#xff1b;可以拉近摄影机&#xff0c;看到图…

SpringBoot 如何使用 @ControllerAdvice 注解进行全局异常处理

SpringBoot 如何使用 ControllerAdvice 注解进行全局异常处理 在 Web 开发中&#xff0c;异常处理是非常重要的一环。在 SpringBoot 框架中&#xff0c;我们通常使用 ExceptionHandler 注解来处理 Controller 层的异常。但是&#xff0c;如果想要处理全局异常&#xff0c;我们…

【MySql】MySql事务常见操作

文章目录 准备工作事务常见操作方式总结 准备工作 将mysql的默认隔离级别设置成读未提交 set global transaction isolation level read uncommitted;注意&#xff1a;设置完毕之后&#xff0c;需要重启终端&#xff0c;进行查看 select tx_isolation 创建测试表 mysql>…

HTML5 的新特性

html基础知识html基础知识_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客html5的新特性HTML5 的新特性_上半场结束&#xff0c;中场已休息&#xff0c;下半场ing的博客-CSDN博客 目录 1.0 HTML5 的新特性 1.1 HTML5 新增的语义化标签 1.2 HTML5 新增的…

LabVIEW何得知是谁在连接远程前面板

LabVIEW何得知是谁在连接远程前面板 想要知道连接远程前面板的用户的身份。如何来得知用户的身份和他们连接远程前面板的时间&#xff1f; 解答: 可以使用Remote Panel: Connections To Clients属性或者Remote Panel Client Connections方法来得知连接远程面板用户的身份。Re…

TypeScript ~ TS 掌握编译文件配置项 ⑤

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; TypeScript ~ TS &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &…

【2023,学点儿新Java-20】流程控制语句关键字及其介绍:while、do、break、continue、return

前情回顾&#xff1a; 【2023&#xff0c;学点儿新Java-19】Java特殊空类型关键字 | Java流程控制语句关键字 | switch-case 选择结构的执行过程&注意点 | 详解&#xff1a;for循环的普通和增强版本【2023&#xff0c;学点儿新Java-18】Java关键字汇总说明 |附&#xff1a…

chatgpt赋能python:Python新手常见的报错提示及解决方法

Python新手常见的报错提示及解决方法 Python是一种非常流行的编程语言。对于新手来说&#xff0c;Python在学习过程中可能会遇到许多报错提示&#xff0c;这些提示可能会让人感到很困惑。本文将介绍Python新手常见的报错提示&#xff0c;并提供解决方法。 IndentationError: …

ninja的简单使用

文章目录 Ninja安装windows环境Linux环境 入门使用与CMake一起使用 Ninja安装 windows环境 问题的解决通常有多种方法。按照结果的好坏程度&#xff0c;可以将解决方法简单的划分为&#xff0c;上中下三个层次&#xff0c;见:为什么谋士总喜欢提上中下三策&#xff1f; 在w…

SpringBoot 如何使用 @RestControllerAdvice 注解进行 RESTful 异常处理

SpringBoot 如何使用 RestControllerAdvice 注解进行 RESTful 异常处理 在 SpringBoot 应用程序中&#xff0c;RESTful 异常处理是一个非常重要的话题。当 RESTful API 出现异常时&#xff0c;我们需要对异常进行处理&#xff0c;以保证 API 的稳定性和可靠性。SpringBoot 提供…

【SpringBoot】SpringBoot的发展沿革,相关介绍,特点,重要策略以及安装步骤讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…