尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java Web招聘系统从设计到实现:架构、数据库与核心代码解析

Java Web招聘系统从设计到实现:架构、数据库与核心代码解析 简介一份基于Java Web的人才招聘系统毕业设计文档面向计算机相关专业的学生适合作为毕业设计、课程设计或项目参考模板。文档完整覆盖从开发背景、技术选型到系统设计实现的全部环节核心功能包含个人求职、企业招聘、管理员审核三大模块涉及JSP、Tomcat、SQL Server及JDBC等技术栈并详细展示了首页、注册登录、求职信息发布等关键页面的设计方案可帮助读者快速理解招聘类网站的开发思路与数据库结构。资源包为单个doc文档大小1.07MB内容包含摘要、目录、章节正文及数据库表说明整体结构清晰便于直接阅读和参照修改。目前已吸引483人学习下载适合需要撰写毕业设计文档或搭建同类系统的开发者作为核心参考资料。1. 从“文档.doc”反推一套能落地的Java Web招聘系统很多人看到“基于Java web的人才招聘系统设计与实现文档.doc”这个标题第一反应是找现成论文或源码但真正到面试或项目汇报时文档里的架构图、数据库设计、核心代码一问三不知反而暴露短板。招聘系统这类CRUD密集型Web项目技术栈并不复杂难点在于把“求职者-职位-简历-投递-面试”这条业务链的路由设计清楚并把Java Web里最容易出问题的会话管理、文件上传、分页查询这几个点做扎实。本文不写某份不存在的文档只讲从业者拿到这个标题会怎么设计方案、怎么写代码、怎么调参、怎么排错让你既能交出文档也能在答辩时扛住追问。Java Web技术选型上Servlet/JSP时代与Spring Boot时代的差异、JDBC与MyBatis的取舍、前端模板渲染方式是决定这个项目“看起来像教学作业”还是“像能上线的系统”的关键分水岭。2. 先定架构与数据模型再谈技术栈选型2.1 招聘系统的核心业务链路与角色权限模型所有人才招聘系统都绕不开五个核心实体用户User、简历Resume、职位Job、投递记录Application、面试安排Interview。角色上分为三类求职者、招聘者HR、管理员。权限控制不该散落在Servlet里到处写if而应该抽象出一个统一的登录态校验过滤器或Spring MVC拦截器按角色URL前缀做粗粒度拦截。常见的路由设计是/candidate/**求职者端投递简历、查看投递状态、维护简历/hr/**招聘者端发布职位、筛选简历、发起面试/admin/**管理员端用户管理、职位审核、数据统计这个设计的好处是在Web服务器层面就能用Filter做路径拦截后端方法上再做细粒度的角色注解形成双层防护。数据库模型上用户表和角色表用中间表关联避免在User表里塞role字段导致后续扩展第三种角色时改表结构。简历和用户是1:1关系但要注意简历内容可能包含多个教育经历、多个工作经历所以要拆成简历主表加经历子表否则后面做简历导出PDF或模板渲染时会因为JSON字段嵌套而痛苦。2.2 Java Web技术栈对比JSP、Servlet传统方案与Spring Boot现代方案如果文档标题里明确写了“Java web”而不是“Spring Boot”可以理解为教学场景偏多但面试官更愿意听你比较过两条技术路线的差异。传统方案是Servlet JSP JDBC Tomcat理由是课程大纲如此部署方式是打WAR包扔进Tomcat的webapps目录。现代方案是Spring Boot Spring MVC MyBatis Plus Thymeleaf用内嵌Tomcat打成可执行JAR直接运行。我一般会这样取舍如果项目要求“写文档、画流程图、答辩演示”选Spring Boot反而更好写。因为Spring Boot的自动配置省去了大量XML配置文档里可以把篇幅留给业务逻辑和数据库设计而不是堆web.xml配置。但需要知道传统方案的几个关键点因为面试必问Servlet生命周期init / service / destroyJSP九大内置对象request、response、session、application等JDBC六步加载驱动、获取连接、创建Statement、执行SQL、处理结果集、关闭资源如果要用传统Servlet方案参考下面这个最小Filter写法用于登录态校验WebFilter(/*) public class AuthFilter implements Filter { private static final ListString WHITE_LIST Arrays.asList(/login, /register, /css, /js, /images); private static final ListString HR_PREFIX Collections.singletonList(/hr/); private static final ListString ADMIN_PREFIX Collections.singletonList(/admin/); Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI().substring(req.getContextPath().length()); String contextPath req.getContextPath(); if (WHITE_LIST.stream().anyMatch(uri::startsWith)) { chain.doFilter(request, response); return; } HttpSession session req.getSession(false); if (session null || session.getAttribute(userId) null) { resp.sendRedirect(contextPath /login); return; } String role (String) session.getAttribute(role); if (HR_PREFIX.stream().anyMatch(uri::startsWith) !hr.equals(role)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } if (ADMIN_PREFIX.stream().anyMatch(uri::startsWith) !admin.equals(role)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } chain.doFilter(request, response); } }这段代码的关键在于白名单放行静态资源否则用户还没登录CSS和JS就被拦截前端页面很难看。另一个细节是req.getSession(false)加false表示如果会话不存在就返回null而不要自动创建一个新Session。若有人伪造请求绕过登录页直接访问受保护资源这里拦截的就是这类未认证请求。角色校验放在URI前缀层虽然不如注解精细但好在简单、直观、不容易漏。2.3 数据库表设计简历与职位两张核心表的字段取舍招聘系统的数据库设计面试官最喜欢问“简历表里为什么要把工作经历拆出去”。设计如下表名t_user字段id, username, password, salt, email, phone, role, status, created_time说明password存的是加盐MD5或SHA-256摘要salt单独一列防止彩虹表攻击。表名t_job字段id, company_name(冗余字段, job_title, job_type, salary_min, salary_max, city, experience_required, degree_required, description_html, publisher_id, status, view_count, created_time说明status用枚举0草稿、1已发布、2已下线。company_name冗余存一份是因为查询列表页时不想每次都JOIN企业表招聘系统高频场景是职位列表冗余可接受。表名t_resume字段id, user_id, real_name, gender, birth_date, phone, email, education_background, work_experience_json, skill_tags, self_evaluation, updated_time说明work_experience_json存JSON数组比如[{company:XX科技,start:2022-01,end:2024-06,role:Java开发}]。这样做的好处是页面渲染时直接解析坏处是无法用SQL做“哪些求职者曾在XX公司工作”的查询。如果文档里强调统计功能就把工作经历拆成t_resume_work子表。SQL建表需要注意字符集DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci否则插入表情符号或生僻字时出现“Incorrect string value”报错。索引上t_job的(status, city, created_time)组合索引能覆盖大多数筛选条件不要对每个字段单独建索引那种做法在数据量上来后反而浪费磁盘写入。DDL核心片段如下CREATE TABLE t_resume ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, real_name VARCHAR(64) DEFAULT NULL, skill_tags VARCHAR(255) DEFAULT NULL, work_experience_json JSON DEFAULT NULL, updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci; CREATE TABLE t_job ( id BIGINT PRIMARY KEY AUTO_INCREMENT, job_title VARCHAR(128) NOT NULL, salary_min INT DEFAULT NULL, salary_max INT DEFAULT NULL, city VARCHAR(64) DEFAULT NULL, status TINYINT DEFAULT 0, view_count INT DEFAULT 0, created_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_status_city_time (status, city, created_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci;这段SQL用好了一个容易被忽略的点简历表对user_id加唯一键从数据库层面保证一个用户只能有一份简历避免并发请求下创建出两条简历。JSON类型字段在MySQL 5.7以后才支持若部署环境是MySQL 5.6需要改成TEXT类型并在Java侧负责序列化。3. 核心功能的Java Web实现登录、投递、分页筛选3.1 登录模块的SHA-256加盐与Session超时控制登录模块是Java Web项目里被问得最多的模块。我见过太多校园项目直接用明文密码比对或者只做一次MD5这类代码在简历上写“熟悉信息安全”时经不起追问。加盐哈希的流程是注册时生成一个随机盐值密码存储值为hash(盐值 明文密码)登录时先查数据库拿到用户记录取出盐计算哈希再比对。注册时加密代码public static String generateSalt() { byte[] bytes new byte[16]; new SecureRandom().nextBytes(bytes); return HexFormat.of().formatHex(bytes); } public static String hashPassword(String rawPassword, String salt) { MessageDigest digest MessageDigest.getInstance(SHA-256); String input salt rawPassword; byte[] hash digest.digest(input.getBytes(StandardCharsets.UTF_8)); return HexFormat.of().formatHex(hash); }技巧点是用SecureRandom而不是Math.random()前者是密码学安全伪随机数生成器CSPRNG后者生成的随机数可预测盐值失去意义。另外哈希时采用“盐值密码”拼接不要反过来否则如果两个用户盐相同虽然概率极低但密码相同哈希值会同前缀。比到MessageDigest.getInstance(SHA-256)即可不要自己写MD5/SHA1Java 8内置支持。Session超时控制有两层。第一层在Tomcat的web.xml或Spring Boot的application.properties里配server.servlet.session.timeout30m第二层在Filter里设置每次操作后刷新Session活性。注意如果系统里用了session.setMaxInactiveInterval()而代码里又设置过setMaxInactiveInterval(0)0表示永不过期这在招聘系统里绝对不要用。求职者简历填到一半放着不动账号被踢出登录体验虽不好但能保护隐私永不超时才会有安全风险。3.2 简历投递的幂等性处理防止用户重复投递同一职位投递功能看似简单就是往t_application表插一条记录但生产环境里最尴尬的问题有两个前端连点两次“立即投递”导致同一个人对同一个职位投出两条记录用户在A页面投递成功在B页面再次投递系统没有提示“已投递过”。解决方式是给表加唯一约束CREATE TABLE t_application ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, job_id BIGINT NOT NULL, status TINYINT DEFAULT 0, apply_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_user_job (user_id, job_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;之后在Java代码里捕获DuplicateKeyException转成业务提示PostMapping(/application) public Result apply(RequestParam Long jobId, HttpSession session) { Long userId (Long) session.getAttribute(userId); try { applicationService.submit(userId, jobId); return Result.success(投递成功); } catch (DuplicateKeyException e) { return Result.error(409, 您已投递过该职位请勿重复投递); } }这个方案的优点是不需要先查一次再插入因为查了也会存在时间窗口并发下照样重复。数据库唯一约束是关键防线。还有一些团队用Redis的Set做投递去重代价是每投递一次要维护两个存储的数据一致性对于一个课设级招聘系统来说过度设计。面试追问时可能会问如果你又要统计“每个职位收到的简历数”又要唯一约束怎么办答案是t_job表增加application_count字段在投递成功后updateapplication_count application_count 1。不要想着去t_application表里count数据量大了会慢如果担心计数不准可以用定时任务核对。3.3 职位筛选列表的多条件SQL拼接与分页参数设计招聘系统列表页一般有这些筛选条件城市、职位类别、薪资范围、学历要求、工作经验。使用MyBatis时最常见的问题是动态SQL里只写where 11被老工程师看到要被说。推荐用where标签自动处理前缀AND或直接写trim。MyBatis XML如下select idsearchJobs resultTypecom.example.entity.Job SELECT id, job_title, salary_min, salary_max, city FROM t_job where if testcity ! null and city ! AND city #{city} /if if testkeyword ! null and keyword ! AND (job_title LIKE CONCAT(%, #{keyword}, %) OR company_name LIKE CONCAT(%, #{keyword}, %)) /if if testsalaryMin ! null AND salary_max gt; #{salaryMin} /if if testsalaryMax ! null AND salary_min lt; #{salaryMax} /if AND status 1 /where ORDER BY created_time DESC LIMIT #{offset}, #{pageSize} /select关于薪资筛选的边界很多人写错。用户选“10K-20K”时应该理解为“职位发布的薪资区间与用户期望区间有交集”也就是salary_max 用户最小值且salary_min 用户最大值而不是salary_min 用户最小值。这个边界条件在文档的“系统设计”部分值得画一张薪资区间交集示意图面试时能说清就是加分项。分页参数上offset不是前端传PageNum给数据库而是(pageNum-1)*pageSize。在MySQL里推荐用LIMIT #{offset}, #{pageSize}但如果要优化大数据量深分页改成WHERE id #{lastId} LIMIT #{pageSize}会更稳定。可以预判面试官问“mysql深分页慢怎么办”这篇设计里给出的答案是列表页只允许跳到前N页后面用下拉加载不让用户输入第1000页每次翻页带上上一页最后一条记录的ID作为游标。页码参数校验也很关键。我见过一个真实事故前端请求pageSize100000pageNum999999后端没限制数据库直接全表扫描把Tomcat线程池打满。所以参数校验必须有if (pageNum 1 || pageSize 50) { throw new BusinessException(非法分页参数); }分页响应封装里除了list还要返回total和pages前端分页器才能渲染页码。total的查询和列表查询分开做不要想着一条SQL用SQL_CALC_FOUND_ROWSMySQL 8.0.17后已废弃该语法老老实实执行SELECT COUNT(*)即可。4. 从“能跑”到“好用”Java Web项目的关键配置与排错4.1 文件上传简历附件与图片的头像上传参数招聘系统通常需要求职者上传简历附件PDF或Word和头像图片。Java Web里如果用Servlet 3.0的MultipartConfig不必引入第三方库但生产环境建议用Spring的MultipartFile配合下面一段配置spring.servlet.multipart.max-file-size5MB spring.servlet.multipart.max-request-size20MB spring.servlet.multipart.enabledtrue如果只配了max-file-size没配max-request-size表单里同时塞多个文件时总大小仍然可能超过限制报MaxUploadSizeExceededException。业界习惯是文件名用UUID重命名防止中文乱码和路径穿越public String storeFile(MultipartFile file, String uploadDir) throws IOException { String originalFilename file.getOriginalFilename(); String ext ; if (originalFilename ! null originalFilename.contains(.)) { ext originalFilename.substring(originalFilename.lastIndexOf(.)); } String newFilename UUID.randomUUID() ext; Path path Paths.get(uploadDir, newFilename); Files.createDirectories(path.getParent()); file.transferTo(path); return newFilename; }关键不是把文件保存到webapp目录下而是存到服务器一个外部目录比如/data/uploads并用一个静态资源映射暴露。这样Web应用重新部署WAR包时上传文件不会丢失。若把文件写到Tomcat的webapps/ROOT下每次重新部署项目文件目录可能被清空。Spring Boot映射方式Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/uploads/**) .addResourceHandler(file: uploadDir /); } }上传文件的格式校验不能只看扩展名把virus.exe改名为resume.pdf后照样上传成功。稳妥的做法是读文件头magic numberPDF文件头是%PDFWord docx是PKZIP格式。Java侧可以读前四个字节做判断不匹配则拒绝。文档里写“仅限制扩展名”会被懂行的人指出漏洞。4.2 跨域、中文乱码与字符编码过滤器招聘系统如果前端是Vue或React独立部署后端Spring Boot接口必然遇到跨域问题。解决方案不是每个接口方法上加CrossOrigin而是注册一个全局过滤器。开发环境允许所有来源生产环境必须限制域名Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOrigin(https://hr.example.com); config.addAllowedMethod(*); config.addAllowedHeader(*); config.setAllowCredentials(true); config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); }注意setAllowCredentials(true)与addAllowedOrigin(*)不能同时使用否则浏览器报错。这属于浏览器规范的限制不是后端能绕过的。老项目JSP模式下乱码问题集中在POST请求参数和响应输出。传统Servlet方案可以在CharacterEncodingFilter里强制UTF-8filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mappingforceEncoding设为true意味着请求和响应都覆盖为UTF-8否则只改请求。Tomcat默认的GET请求URI编码不是UTF-8若URL里带中文参数还得改server.xml的URIEncodingUTF-8。Spring Boot中则直接配置server.servlet.encoding.charsetUTF-8与server.servlet.encoding.forcetrue。4.3 Nginx部署Java Web项目的反向代理与静态资源缓存如果文档最后有一章“系统部署”写Nginx部署多web项目会是亮点。常见架构是Nginx监听80端口按路径把请求反向代理到不同Java应用端口。比如招聘系统部署在Tomcat的8080端口前端页面或另一个Web项目部署在8090端口server { listen 80; server_name hr.example.com; location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /uploads/ { proxy_pass http://127.0.0.1:8080/uploads/; expires 7d; add_header Cache-Control public; } }proxy_pass http://127.0.0.1:8080/;末尾带斜杠与不带斜杠含义不同。带斜杠会把/api/xxx代理转发为/xxx去掉斜杠则保留/api/xxx作为完整路径。这个细节搞错接口路由立刻404。Java应用本身只监听内网地址不让外部直接访问8080通过Nginx统一暴露。用server { listen 127.0.0.1:8080; }或防火墙规则限制来源端口是Nginx多Web项目部署的常见做法目的是让Nginx统一做TLS终结和静态缓存。文档里能将Nginx配置背景下的“正向代理与反向代理区别”写清楚比多画一张UML图实在。5. 面试答辩与文档写作把Java Web招聘系统讲出区分度5.1 面试官最爱的三个高频追问及应答思路“你这个招聘系统怎么保证简历数据不丢失”不要只说“数据库有事务”而是分两层答应用层在简历更新操作上开启事务涉及t_resume主表与t_resume_work子表主表更新成功但子表失败时整体回滚用Transactional注解来声明数据库层定期备份binlog或mysqldump。同时简历附件上传采用先传临时目录、确认业务成功后再move到正式目录的策略避免孤儿文件。“职位搜索为什么不用全文检索”如果系统只支持LIKE模糊查询当简历或职位数据量达到百万级时LIKE %java%会全表扫描。答辩话术是当前阶段业务量小LIKE够用如果数据量增长预留两种升级方案MySQL全文索引自然语言模式或引入Elasticsearch。但不要主动说已经用了Elasticsearch然后被追问集群配置时答不上来。“Session共享怎么做项目部署多台Tomcat怎么办”单机项目不需要Session共享但如果要在文档里写高可用就要知道以下知识而不是说“配置一下就行”。常规方案有三种Session黏滞负载均衡器按用户绑定固定节点、Session复制Tomcat集群间广播、Session外置存储Redis。第三种是目前首选Spring Boot配合Spring Session的Redis支持只需三步dependency groupIdorg.springframework.session/groupId artifactIdspring-session-data-redis/artifactId /dependencyspring.session.store-typeredis spring.redis.host127.0.0.1 spring.redis.port6379配置后原来从HttpSession里读userId的代码不用改底层存储自动切到Redis。这套方案面试时可以展开讲序列化方式的坑也接得住——Spring Session默认JDK序列化Redis里存的是二进制排查问题时redis-cli get看到的是一堆反斜杠转义可以在RedisSerializer配置为Jackson JSON代价是无法对所有类型都通用。5.2 正则表达式校验手机号和邮箱常见错误与改进写法用户注册页的校验不能只靠前端后端必须再校验一次。直接写一个宽松的正则可能会让非法数据入库写死了又可能拒绝合法号码。Java侧校验手机号时简单用^1[3-9]\\d{9}$能覆盖中国大陆11位手机号大部分情况但要注意一年内新增号段比如19x开头现在已经很普遍这个正则用[3-9]已经覆盖。邮箱校验则是个大坑Java内置的InternetAddress类校验过于宽松前后内容都可能被绕过所以辅助正则private static final Pattern EMAIL_PATTERN Pattern.compile( ^[A-Za-z0-9._%-][A-Za-z0-9.-]\\.[A-Za-z]{2,}$ );部门评审时曾有人提出这个正则不允许邮箱用户名是纯数字域名事实上纯数字域名比如123456.com是合法邮箱正则中[A-Za-z0-9]已包含数字。后端校验失败时统一抛异常由全局异常处理器返回层次结构一致的JSON响应格式比如{ code: 400, message: 手机号格式不正确, data: null }这样前端不管用axios还是fetch都能统一处理错误提示而不用纠结后端返回的是Bad Request还是自定义结构。5.3 设计文档的过审技巧把“功能模块”画成“业务时序图”招聘系统的设计与实现文档通常要有功能模块图、数据库ER图、时序图、界面图。很多教程类文档把功能模块图画成分层矩形框说实话答辩老师早就看腻了。更务实的做法是给“投递简历”这个核心流程画一张时序图把浏览器、Controller、Service、Dao、MySQL消息之间的调用顺序画清楚能体现独立思考。实现层面投递简历的Service层代码要分两层写Transactional public void submit(Long userId, Long jobId) { Job job jobMapper.selectById(jobId); if (job null || job.getStatus() ! 1) { throw new BusinessException(职位不存在或已下线); } Resume resume resumeMapper.selectByUserId(userId); if (resume null) { throw new BusinessException(请先完善简历); } ResumeWorkExample example new ResumeWorkExample(); example.createCriteria().andResumeIdEqualTo(resume.getId()); long workCount resumeWorkMapper.countByExample(example); if (workCount 0 resume.getSelfEvaluation() null) { throw new BusinessException(简历内容过少请补充后投递); } if (applicationMapper.checkExists(userId, jobId) 0) { throw new BusinessException(您已投递过该职位); } applicationMapper.insert(userId, jobId); jobMapper.addViewOrApplyCount(jobId, 1); }注意事务注解的粒度与自调用问题。submit方法加Transactional但调用方Controller如果在这个类内部直接this调用Spring的AOP代理会失效需要注入自己或拆单独Service类。这是最常见的Java Web面试题“为什么同类内调用事务不生效”。文档的代码演练部分把这段带注释写上答辩效果远好于贴一段完整的但没人懂的框架代码。6. 用JMeter做一次简单的Java Web招聘系统性能验证系统做完了文档里最后可以加一页“性能测试”证明你验证过。不要拿一百多万数据吹牛就做一轮最小但可信的压测模拟50个求职者并发投递简历。JMeter线程组设置50线程、循环10次断言响应码是200且响应JSON中的code为0。测试前需要先清空t_application表中测试账号的数据否则500次请求里大多数会命中唯一键冲突压测结果会显示大量409错误。这不是系统性能差而是幂等设计在起作用但不懂的人会误判。测试脚本片段import org.apache.jmeter.assertions.AssertionResult; def response prev.getResponseDataAsString() if (!response.contains(code:0)) { AssertionResult result new AssertionResult(BusinessCodeCheck) result.setFailure(true) result.setFailureMessage(业务code非0响应 response) prev.addAssertionResult(result) }这段Groovy脚本从prev对象拿上次请求的响应体检查code:0若不通过则添加断言失败。JMeter的响应断言自带工具可以做到同样的事但这个脚本的好处是能打印具体响应方便在“查看结果树”里定位是被限流还是业务校验拦截。作为卖点在此刻指出这不是在压“能跑多快”而是压“重复投递正确失败后服务器的处理能力”。系统设计的简历投递瓶颈往往不是数据库写而是t_application的唯一索引更新。SQL分析执行计划时type应显示为const或eq_ref如果出现ALL说明索引没建到位。压测结束后顺手执行一句慢查询分析SHOW GLOBAL STATUS LIKE Slow_queries;如果数值过大优先看EXPLAIN SELECT * FROM t_application WHERE user_id ? AND job_id ?重点看possible_keys是不是uk_user_job。多数情况下问题出在MyBatis Mapper XML里写了FOR UPDATE把行锁范围扩大成了表锁这个坑在低并发看不出一旦压到100并发事务等待时间就会直线上升。本文还有配套的精品资源点击获取
返回列表