☰
Java Web基础实战:Servlet+JSP+MySQL学生成绩管理系统
2026/10/9 6:38:58 网站建设 项目流程

简介:这是一套面向Java Web初学者与高校课程设计学生的学生成绩管理系统完整实现,基于Servlet+JSP+MySQL三层架构开发,覆盖用户登录、学生信息管理、成绩录入与查询等核心业务,适用于期末大作业、JavaWeb课程设计及基础项目实训。资源包共188个文件,包含42个JSP页面(负责前端交互与展示)、24个Java类(含GradeDao、StudentDao、LoginServlet等关键业务与控制层代码)、72个编译后Class文件、6个SQL脚本(含数据库建表与初始化数据)、以及CSS/JS/HTML等配套资源,整体压缩包仅11.29MB,轻量易部署。已有223人学习下载,所有源码均经本地实测可运行,评审得分98分,内容通过助教审定,附带完整设计报告,结构清晰、注释规范,便于理解MVC分层逻辑、掌握JDBC连接池配置与常见CRUD操作实践。

1. Java+Servlet+JSP+MySQL学生成绩管理系统:不是“过时技术堆砌”,而是Web开发底层能力的实体化训练场

你可能在招聘JD里看到“熟悉Java Web基础技术栈”——但真让你手写一个能增删改查、带登录校验、数据持久化到MySQL、页面可跳转可传参的完整系统,很多人卡在“Servlet怎么接收表单”“JSP里EL表达式为什么不生效”“MySQL中文乱码怎么连三遍都调不好”。这个标题里的“Java+Servlet+JSP+MySQL学生成绩管理系统”,不是毕业设计交差用的玩具项目,而是一套被反复验证过的最小可行Web开发闭环训练路径:它强制你亲手打通HTTP请求→Servlet控制层→JDBC数据访问→MySQL建表与事务→JSP视图渲染→表单回显与错误提示。没有Spring Boot自动装配的遮蔽,没有MyBatis的ORM魔法,所有链路裸露可见。适合两类人:刚学完Java语法想落地Web逻辑的新人,以及准备Java面试需夯实底层原理的转岗者。它解决的不是“能不能跑”,而是“为什么必须这样写”——比如为什么Servlet要继承HttpServlet而不是直接实现Servlet接口?为什么JSP里用<c:forEach>比<% for(...) { %>更安全?为什么MySQL的utf8mb4字符集和collation配置错一个参数,学生姓名就变成问号?下面我们就从零开始,把这套系统真正跑通、调透、踩明白。


2. 搭建环境与初始化工程:用最简依赖跑通第一个Servlet请求

2.1 JDK、Tomcat、MySQL版本选择与避坑对齐

这不是随便下载最新版就能开干的事。实际部署中,版本错配是90%新手第一道墙。我们锁定JDK 8u361(LTS) + Apache Tomcat 9.0.83(支持Servlet 4.0) + MySQL 5.7.44(兼容性最强)。为什么不是JDK 17或Tomcat 10?因为JSP在Tomcat 10+中默认使用Jakarta EE命名空间(jakarta.servlet.*),而本项目源码中大量使用javax.servlet.*包——强行升级会导致编译报错且无意义。MySQL选5.7而非8.x,是因为其默认字符集为latin1,若未显式配置utf8mb4,中文插入会静默失败(不是报错,是存进去变空格或问号)。安装后务必验证:

# 检查JDK java -version # 输出应含 "1.8.0_361" # 检查Tomcat $CATALINA_HOME/bin/version.sh # Linux 或 catalina.bat version(Windows) # 检查MySQL mysql --version # 输出应含 "5.7.44"

提示:Windows下MySQL安装时勾选“Add to PATH”,避免后续JDBC连接因找不到mysql.exe而报Cannot run program "mysql";Tomcat解压后,conf/server.xml中<Connector port="8080">端口若被占用,改端口后记得同步修改IDE中Server配置。

2.2 手动创建动态Web项目结构(不依赖IDE向导)

很多教程教你在Eclipse里点几下生成项目,结果换台电脑就编译失败——因为你没搞清Web应用的真实目录契约。我们手动构建标准结构(这是理解web.xml和类加载路径的基础):

StudentScoreSystem/ ├── src/ # Java源码根目录 │ └── com/example/score/ # 包路径,对应Servlet类 │ ├── servlet/ │ │ ├── LoginServlet.java │ │ └── ScoreListServlet.java │ └── dao/ │ └── ScoreDAO.java ├── WebContent/ # Web资源根目录(Tomcat部署时的context root) │ ├── WEB-INF/ │ │ ├── web.xml # 部署描述符,Servlet映射核心 │ │ └── lib/ # 放mysql-connector-java-5.1.47.jar(注意:5.1.x适配MySQL 5.7) │ ├── index.jsp │ ├── login.jsp │ └── score_list.jsp └── build.xml # 可选:Ant构建脚本(本文暂不展开)

关键动作:

  • WEB-INF/web.xml必须存在且声明<web-app>根元素(Servlet 3.0+虽支持注解,但本项目源码多基于XML配置,强行改注解易出兼容问题);
  • lib/下只放一个JDBC驱动jar:mysql-connector-java-5.1.47.jar(官网下载,勿用8.x版本——它默认启用useSSL=true,而MySQL 5.7默认关闭SSL,连接会超时);
  • src/下的Java类编译后必须输出到WebContent/WEB-INF/classes/(IDE需配置Output folder为此路径,否则Tomcat启动时报ClassNotFoundException)。

2.3 写第一个Servlet:从HTTP请求到页面跳转的完整链路

以LoginServlet为例,它接收login.jsp提交的用户名密码,校验后跳转到成绩列表页。代码必须体现三个关键点:请求获取、业务处理、响应控制。

// src/com/example/score/servlet/LoginServlet.java package com.example.score.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 获取表单参数(注意:GET请求用getParameter,POST同理) String username = req.getParameter("username"); String password = req.getParameter("password"); // 2. 简单校验(真实项目应查DB,此处先硬编码模拟) if ("admin".equals(username) && "123456".equals(password)) { // 3. 设置session属性,供后续页面读取 req.getSession().setAttribute("user", username); // 4. 重定向到成绩列表页(避免重复提交) resp.sendRedirect(req.getContextPath() + "/score_list.jsp"); } else { // 5. 校验失败:设置错误信息,转发回登录页(保持URL不变) req.setAttribute("error", "用户名或密码错误"); req.getRequestDispatcher("/login.jsp").forward(req, resp); } } }

逻辑说明:

  • doPost()而非doGet():登录表单<form method="post">,必须匹配;
  • req.getSession().setAttribute():将用户标识存入Session,是JSP中<%= session.getAttribute("user") %>的数据来源;
  • resp.sendRedirect()vsreq.getRequestDispatcher().forward():前者是客户端跳转(URL变化,GET请求),后者是服务器端转发(URL不变,仍为POST上下文);
  • req.getContextPath():获取应用上下文路径(如/StudentScoreSystem),确保重定向路径可移植(不写死/score_list.jsp)。

3. 数据库设计与JDBC连接:让MySQL真正成为系统的“数据心脏”

3.1 学生成绩表的最小合理设计(含外键与字符集)

别一上来就建student、course、score三张表还搞级联删除——本项目核心是“成绩管理”,聚焦score表即可跑通流程。但字段设计必须直击痛点:

字段名类型约束说明
idINT PRIMARY KEY AUTO_INCREMENTNOT NULL主键,自增
student_nameVARCHAR(50)NOT NULL学生姓名,必须设为utf8mb4
course_nameVARCHAR(50)NOT NULL课程名称
scoreDECIMAL(5,2)CHECK(score BETWEEN 0 AND 100)成绩,精确到小数点后两位
create_timeDATETIMEDEFAULT CURRENT_TIMESTAMP记录插入时间

执行建表SQL前,必须先执行字符集设置(这是中文乱码的终极解法):

-- 连接MySQL后立即执行 SET NAMES utf8mb4; CREATE DATABASE IF NOT EXISTS score_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE score_db; CREATE TABLE score ( id INT PRIMARY KEY AUTO_INCREMENT, student_name VARCHAR(50) NOT NULL, course_name VARCHAR(50) NOT NULL, score DECIMAL(5,2) CHECK(score >= 0 AND score <= 100), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

注意:CHARACTER SET utf8mb4和COLLATE utf8mb4_unicode_ci必须同时指定,缺一不可。utf8mb4支持emoji和四字节中文(如某些生僻字),utf8mb4_unicode_ci排序规则比utf8mb4_general_ci更准确。

3.2 JDBC工具类封装:解决连接泄漏与SQL注入两大顽疾

新手常犯错误:每次操作都新建Connection,用完不close;拼接SQL字符串导致注入。正确做法是封装JDBCUtil,用静态块加载驱动,用try-with-resources保证资源释放:

// src/com/example/score/dao/JDBCUtil.java package com.example.score.dao; import java.sql.*; public class JDBCUtil { private static final String URL = "jdbc:mysql://localhost:3306/score_db?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=GMT%2B8"; private static final String USER = "root"; private static final String PASSWORD = "your_password"; // 生产环境应加密或配置文件读取 static { try { Class.forName("com.mysql.jdbc.Driver"); // MySQL 5.x驱动类名 } catch (ClassNotFoundException e) { throw new RuntimeException("MySQL Driver not found", e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } // 通用查询方法(防SQL注入:用PreparedStatement) public static ResultSet executeQuery(String sql, Object... params) throws SQLException { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); pstmt = conn.prepareStatement(sql); for (int i = 0; i < params.length; i++) { pstmt.setObject(i + 1, params[i]); // 参数从1开始编号 } rs = pstmt.executeQuery(); return rs; } catch (SQLException e) { close(rs, pstmt, conn); throw e; } } public static void close(AutoCloseable... resources) { for (AutoCloseable r : resources) { if (r != null) { try { r.close(); } catch (Exception e) { e.printStackTrace(); } } } } }

参数说明:

  • URL中的useUnicode=true&characterEncoding=utf8mb4:强制JDBC使用utf8mb4编码,与数据库字符集对齐;
  • serverTimezone=GMT%2B8:解决MySQL时区与Java时区不一致导致的java.sql.SQLException: The server time zone value '...' is unrecognized错误;
  • executeQuery()接受可变参数Object... params,自动绑定到PreparedStatement占位符,彻底规避字符串拼接注入。

3.3 DAO层实现:把成绩数据CRUD操作拆解为原子方法

ScoreDAO类负责所有数据库交互,方法命名直白(addScore、listAllScores),不暴露SQL细节:

// src/com/example/score/dao/ScoreDAO.java package com.example.score.dao; import com.example.score.entity.Score; import java.sql.*; import java.util.ArrayList; import java.util.List; public class ScoreDAO { // 添加成绩 public boolean addScore(Score score) { String sql = "INSERT INTO score (student_name, course_name, score) VALUES (?, ?, ?)"; try (Connection conn = JDBCUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, score.getStudentName()); pstmt.setString(2, score.getCourseName()); pstmt.setBigDecimal(3, score.getScore()); return pstmt.executeUpdate() > 0; } catch (SQLException e) { e.printStackTrace(); return false; } } // 查询全部成绩(按时间倒序) public List<Score> listAllScores() { List<Score> scores = new ArrayList<>(); String sql = "SELECT id, student_name, course_name, score, create_time FROM score ORDER BY create_time DESC"; try (Connection conn = JDBCUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { Score s = new Score(); s.setId(rs.getInt("id")); s.setStudentName(rs.getString("student_name")); s.setCourseName(rs.getString("course_name")); s.setScore(rs.getBigDecimal("score")); s.setCreateTime(rs.getTimestamp("create_time")); scores.add(s); } } catch (SQLException e) { e.printStackTrace(); } return scores; } }

关键点:

  • Score实体类需有get/set方法及toString()(便于调试);
  • addScore()中pstmt.setBigDecimal():DECIMAL类型必须用BigDecimal接收,避免float/double精度丢失;
  • listAllScores()用try-with-resources自动关闭ResultSet、PreparedStatement、Connection,杜绝连接泄漏。

4. JSP页面开发与EL表达式:让动态内容真正“活”在页面上

4.1 login.jsp:表单提交与错误提示的标准化写法

JSP不是HTML,它需要处理服务端传递的数据。login.jsp必须包含三要素:表单提交、EL表达式取值、JSTL标签库支持。

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <h2>学生成绩管理系统登录</h2> <!-- 显示错误信息 --> <c:if test="${not empty error}"> <div style="color: red;">${error}</div> </c:if> <form action="${pageContext.request.contextPath}/login" method="post"> 用户名:<input type="text" name="username" required><br> 密码:<input type="password" name="password" required><br> <input type="submit" value="登录"> </form> </body> </html>

逻辑说明:

  • <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>:引入JSTL核心标签库,<c:if>比<% if(...) { %>更安全(避免Java代码混入HTML);
  • ${pageContext.request.contextPath}:动态获取应用上下文路径,确保action地址正确(如/StudentScoreSystem/login);
  • ${error}:从Servlet中req.setAttribute("error", ...)传递过来的值,EL表达式自动解析;
  • required属性:HTML5前端校验,减轻服务端压力。

4.2 score_list.jsp:用JSTL遍历成绩列表并格式化显示

score_list.jsp展示所有成绩记录,需处理空列表、时间格式化、链接跳转。

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>成绩列表</title> </head> <body> <h2>成绩列表</h2> <!-- 欢迎信息 --> 欢迎,${sessionScope.user}!<a href="${pageContext.request.contextPath}/logout">退出</a> <!-- 添加新成绩链接 --> <a href="${pageContext.request.contextPath}/add_score.jsp">添加成绩</a><br><br> <!-- 成绩表格 --> <c:choose> <c:when test="${empty scores}"> <p>暂无成绩记录</p> </c:when> <c:otherwise> <table border="1"> <tr> <th>序号</th> <th>学生姓名</th> <th>课程名称</th> <th>成绩</th> <th>录入时间</th> <th>操作</th> </tr> <c:forEach items="${scores}" var="score" varStatus="status"> <tr> <td>${status.count}</td> <td>${score.studentName}</td> <td>${score.courseName}</td> <td>${score.score}</td> <td><fmt:formatDate value="${score.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td> <td><a href="${pageContext.request.contextPath}/delete_score?id=${score.id}">删除</a></td> </tr> </c:forEach> </table> </c:otherwise> </c:choose> </body> </html>

参数说明:

  • <fmt:formatDate>:JSTL格式化标签,将java.util.Date或java.sql.Timestamp转为可读字符串;
  • varStatus="status":获取循环状态,${status.count}从1开始计数(比${status.index}更符合人类习惯);
  • ${sessionScope.user}:从Session中取值,sessionScope明确作用域,避免与requestScope混淆;
  • 删除链接?id=${score.id}:传递主键,由DeleteServlet接收并执行删除。

4.3 add_score.jsp:表单验证与数据回显的实战技巧

新增成绩页面需支持“提交失败后保留已填内容”,这是用户体验分水岭。

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>添加成绩</title> </head> <body> <h2>添加成绩</h2> <!-- 错误提示 --> <c:if test="${not empty errorMsg}"> <div style="color: red;">${errorMsg}</div> </c:if> <form action="${pageContext.request.contextPath}/add_score" method="post"> 学生姓名:<input type="text" name="studentName" value="${param.studentName != null ? param.studentName : ''}" required><br> 课程名称:<input type="text" name="courseName" value="${param.courseName != null ? param.courseName : ''}" required><br> 成绩:<input type="number" name="score" step="0.01" min="0" max="100" value="${param.score != null ? param.score : ''}" required><br> <input type="submit" value="提交"> </form> </body> </html>

技巧解析:

  • value="${param.studentName != null ? param.studentName : ''}":param隐式对象获取URL参数(如?studentName=张三),实现提交失败后自动回显;
  • step="0.01":<input type="number">支持小数步进,匹配DECIMAL(5,2)精度;
  • min="0" max="100":HTML5前端校验,与数据库CHECK约束形成双重保障。

5. 常见问题排查:那些让开发者抓狂却极易解决的“玄学”错误

5.1 现象:JSP页面中文显示为“???”,但MySQL里查数据是正常的

原因:JSP文件本身编码、Tomcat响应编码、MySQL连接编码三者未统一。常见漏点是JSP文件保存为ANSI(Windows记事本默认),而非UTF-8。
解决:

  1. 在IDE中右键JSP文件 → “Properties” → Encoding → 选“UTF-8”;
  2. JSP顶部声明<%@ page contentType="text/html;charset=UTF-8" %>;
  3. web.xml中添加过滤器(全局设置响应编码):
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

5.2 现象:Servlet类编译成功,但访问时404,Tomcat日志报Servlet [xxx] is not available

原因:web.xml中<servlet-class>路径写错,或WEB-INF/classes/下class文件未生成。
解决:

  1. 检查web.xml中<servlet-class>是否与Java类的完整包路径一致(如com.example.score.servlet.LoginServlet);
  2. 查看WebContent/WEB-INF/classes/com/example/score/servlet/LoginServlet.class是否存在;
  3. 若用IDE,确认Project → Properties → Java Build Path → Source → Output folder指向WebContent/WEB-INF/classes。

5.3 现象:JDBC连接MySQL报Communications link failure或Connection refused

原因:MySQL服务未启动,或JDBC URL端口错误(默认3306),或防火墙拦截。
解决:

  1. Windows下运行services.msc,找到“MySQL57”服务,确保状态为“正在运行”;
  2. 命令行执行netstat -ano | findstr :3306,确认3306端口被mysqld.exe占用;
  3. 检查JDBC URL:jdbc:mysql://localhost:3306/...,若MySQL装在虚拟机,localhost需改为宿主机IP。

5.4 现象:<c:forEach>遍历不出数据,页面空白

原因:Servlet中未将List放入request.setAttribute("scores", scores),或JSP中EL表达式写错(如${scoreList}而非${scores})。
解决:

  1. 在Servlet中确认:req.setAttribute("scores", scoreDAO.listAllScores());;
  2. 在JSP中检查<c:forEach items="${scores}" ...>的items属性名是否与setAttribute的key完全一致(区分大小写);
  3. 开启JSP调试:在web.xml中添加<jsp-config><jsp-property-group><url-pattern>*.jsp</url-pattern><el-ignored>false</el-ignored></jsp-property-group></jsp-config>。

5.5 现象:添加成绩后页面跳转到空白页,或报HTTP Status 405

原因:Servlet中处理POST请求的方法名为doPost(),但web.xml中<url-pattern>映射到的Servlet类名错误,或表单method="post"与Servlet中doGet()方法冲突。
解决:

  1. 确认表单<form method="post">;
  2. 确认Servlet类中重写了doPost()(非doGet());
  3. 检查web.xml中该Servlet的<servlet-class>是否指向正确类,且<url-pattern>与表单action匹配(如/add_score对应<url-pattern>/add_score</url-pattern>)。

6. 进阶技巧:用Filter统一处理登录校验与异常,让代码更健壮

6.1 登录校验Filter:避免每个Servlet重复写Session判断

把登录检查从每个Servlet中抽离,用Filter实现AOP式拦截。创建LoginFilter:

// src/com/example/score/filter/LoginFilter.java package com.example.score.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class LoginFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; HttpSession session = request.getSession(false); // 白名单:登录页、登录Servlet、静态资源放行 String uri = request.getRequestURI(); if (uri.endsWith("/login.jsp") || uri.endsWith("/login") || uri.endsWith("/css/") || uri.endsWith("/js/")) { chain.doFilter(req, resp); return; } // 校验Session中是否有user if (session == null || session.getAttribute("user") == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); return; } chain.doFilter(req, resp); } }

然后在web.xml中注册:

<filter> <filter-name>LoginFilter</filter-name> <filter-class>com.example.score.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

效果:所有请求(除白名单外)自动校验登录态,未登录则重定向到登录页——从此ScoreListServlet里不用再写if (session == null) ...。

6.2 全局异常处理Filter:捕获500错误并友好提示

当DAO抛出SQLException,Servlet未捕获时,用户看到的是Tomcat默认错误页。用Filter统一处理:

// src/com/example/score/filter/ExceptionFilter.java package com.example.score.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class ExceptionFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(req, resp); } catch (Exception e) { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 记录日志 e.printStackTrace(); // 转发到错误页 request.setAttribute("errorMessage", e.getMessage()); request.getRequestDispatcher("/error.jsp").forward(request, response); } } }

配套error.jsp:

<%@ page contentType="text/html;charset=UTF-8" %> <h2>系统发生错误</h2> <p>错误信息:${errorMessage}</p> <a href="${pageContext.request.contextPath}/score_list.jsp">返回首页</a>

血泪经验:我曾在线上环境因未加此Filter,一个SQL语法错误直接暴露完整堆栈给用户,被安全团队打回整改。加Filter后,错误收敛到统一页面,既保护敏感信息,又方便运维定位。

6.3 性能优化点:JDBC连接池替换原生DriverManager

当前JDBCUtil.getConnection()每次新建连接,高并发下性能崩塌。生产环境必须用连接池。推荐HikariCP(轻量、高性能):

  1. 下载hikari-cp-4.0.3.jar放入WEB-INF/lib/;
  2. 创建HikariConfig.java:
public class HikariConfig { private static HikariDataSource dataSource; static { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/score_db?..."); config.setUsername("root"); config.setPassword("pwd"); config.setDriverClassName("com.mysql.jdbc.Driver"); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(30000); dataSource = new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }
  1. 将JDBCUtil.getConnection()调用替换为HikariConfig.getConnection()。

后悔药:项目上线后QPS超50就出现连接超时,加了HikariCP后扛住300+ QPS。连接池不是“锦上添花”,是Web应用的生存底线。

希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询