☰
JSP+SQL宠物诊所系统:从部署到改造的全流程指南
2026/10/7 12:47:32 网站建设 项目流程

简介:一份面向宠物诊所信息化管理的JSP与SQL数据库项目完整资料,适合Java Web学习者、课程设计或毕业设计开发者参考。资源以“爱心宠物诊所”系统为例,涵盖需求分析、系统架构设计、MVC分层实现、数据库表设计以及JSP动态交互页面等内容,能够帮助理解动态网页与关系型数据库的配合方式。数据库设计包含宠物资料、就诊记录、药品库存等核心表,通过外键关联保证数据一致性;JSP页面与Servlet、JavaBeans配合实现数据的查询、添加、更新、删除等操作。压缩包共446个文件,大小约2.55MB,主要包含38个Java源文件、83个class文件、26个JSP页面,以及XML配置、jar依赖库、项目备份等,覆盖控制器、业务逻辑、数据库连接配置和初始化建表脚本。另附文章说明文档,便于按步骤完成部署、运行与二次开发。已有334人学习下载,适合希望获取完整源码和配套讲解来掌握JavaWeb项目开发流程的读者。

1. 先认清这个压缩包是什么:JSP+SQL的宠物诊所系统值不值得跑起来

拿到“基于JSP和SQL数据库的宠物诊所系统的设计与实现”这个压缩包,第一件事不是急着解压,而是想清楚它到底是什么形态。这类资源大多是课程设计或毕业设计产物:JSP 页面负责展示和接收请求,SQL 数据库存宠物、主人、就诊记录这些核心数据,两者通过 JDBC 连起来,再丢进 Tomcat 就能跑。它解决的是入门者最关心的一个问题:一个 Java Web 项目从建表到页面展示的完整链路长什么样。适合正在做课设、刚接触 JSP 项目、或者要接手老系统的人。别指望它有多高的生产可用性,但把它跑通、读懂、能改,比看十篇教程都实在。

2. 解压后的骨架:源码、数据库脚本和说明文档各自负责什么

2.1 先按“代码、数据、文档”三堆整理压缩包内容

解压后不要急着双击说明文档,先把文件按类型摊开。典型课程设计压缩包里有三类东西:JSP 源码(通常是整个 Web 项目目录)、数据库脚本(一个或几个 .sql 文件)、文章说明(Word/PDF,讲设计思路和操作步骤)。有些打包者还会把 MySQL 驱动 jar 放在 WEB-INF/lib 下,这是好事,说明不用自己补依赖;没放的话,后面连接数据库必报 ClassNotFoundException。

先把项目目录结构读明白。常见 JSP 项目根目录下有 index.jsp、login.jsp 这类页面文件,WEB-INF 下是 web.xml 和 classes 目录。web.xml 是部署描述符,决定欢迎页是哪个、Servlet 映射到什么 URL,先花十分钟读它,比乱点页面更快摸清系统入口。若说明文档里写了数据库名和默认账号,也记下来;若没写,就去源码里全局搜“jdbc:mysql”,连接串里藏着数据库名。

2.2 宠物诊所业务对应的表设计:主人、宠物、就诊记录是三条主线

无论压缩包里具体表名怎么起,宠物诊所系统的数据库核心就三张业务表加一张登录表。主人表(owner)存宠物主联系方式,宠物表(pet)存宠物档案和照片路径,就诊记录表(record)存每次看病的诊断与用药。登录表(user)是 JSP 登录功能的凭证来源。表之间通过外键关联:一个主人可以养多只宠物,一只宠物可以有多条就诊记录。

我一般会根据源码里的 SQL 脚本反推业务,而不是照着文章说明背。脚本里能看出设计者有没有做约束:外键有没有建、时间字段是 DATETIME 还是字符串、字符集是不是 utf8mb4。这些直接决定你后面改代码时会不会被数据格式坑到。比如时间字段用 VARCHAR 存,排序和区间查询就特别难受,这就是课程设计最常见的偷懒方式。

数据库脚本通常长这样:

CREATE DATABASE IF NOT EXISTS pet_clinic DEFAULT CHARACTER SET utf8mb4; USE pet_clinic; CREATE TABLE pet_owner ( owner_id INT PRIMARY KEY AUTO_INCREMENT, owner_name VARCHAR(50) NOT NULL, phone VARCHAR(20), address VARCHAR(100) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE pet ( pet_id INT PRIMARY KEY AUTO_INCREMENT, owner_id INT NOT NULL, pet_name VARCHAR(50) NOT NULL, species VARCHAR(20), breed VARCHAR(30), photo_path VARCHAR(200), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (owner_id) REFERENCES pet_owner(owner_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE medical_record ( record_id INT PRIMARY KEY AUTO_INCREMENT, pet_id INT NOT NULL, doctor_name VARCHAR(50), diagnosis VARCHAR(500), treatment VARCHAR(500), visit_date DATETIME, FOREIGN KEY (pet_id) REFERENCES pet(pet_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这段脚本把三张核心表建出来,外键和字符集都设置好。这里的要点是:pet_owner 是主表,pet 依赖它,medical_record 又依赖 pet,所以导入时必须先建主表再建子表,否则外键会报错。字符集用 utf8mb4 而不是 utf8,是为了能存宠物名字里的生僻字和 Emoji 字符,课程设计不设这个,后面十有八九要被中文乱码折磨。

2.3 找不到数据库脚本时,用源码反推表结构

偶尔会遇到压缩包里没带 .sql 文件的情况。先别骂打包的人,JSP 项目里通常有备份:WEB-INF/classes 下可能有 init.sql,或者说明文档附录里贴了建表语句。实在都没有,就把 DAO 层打开,看 SQL 里的字段名,反向拼出表结构。这种做法不优雅,但能救命。

搜“CREATE TABLE”和“INSERT INTO”是定位表结构最快的入口。IDE 里用全局搜索,或者命令行 grep,比肉眼翻文件快得多。我一般会先把所有 .jsp 文件里的表单字段和 DAO 里的查询字段拉出来对比,确认哪些字段真正在用,再去 MySQL 里手动建表。注意别漏了外键关系:宠物表里一定有个 owner_id 或类似字段指向主人表,就诊记录一定有个 pet_id,这种关联关系直接决定后面做增删改查时级联操作用不用的上。

3. 本地跑通的最小部署:Tomcat、MySQL 与 JDBC 参数匹配

3.1 版本矩阵:JSP 项目对环境最敏感,版本错了跑不动

JSP 项目不像 Spring Boot 那样一个 jar 打天下,它对环境挑剔得很。适合课程设计 JSP 项目的常见组合是:JDK 8 配 Tomcat 8.5 或 9.0,数据库用 MySQL 5.7 或 8.0。JDK 11 以上不是不能跑,但老项目里的 jar 可能没适配,会出现莫名奇妙的 NoClassDefFoundError。与其折腾,不如老老实实装 JDK 8。

MySQL 版本和驱动版本是关键。Connector/J 5.x 对应 MySQL 5.x,驱动类是 com.mysql.jdbc.Driver;Connector/J 8.x 对应 MySQL 8.x,驱动类必须改成 com.mysql.cj.jdbc.Driver。如果你本地装的是 MySQL 8.0,但源码里写的是老驱动类名,启动会直接报 ClassNotFoundException。反过来,MySQL 5.7 配新驱动也可能握手失败。下表是我常用的匹配矩阵:

组件推荐版本说明
JDK1.8对老 JSP 项目兼容性最好
Tomcat8.5 / 9.0支持 Servlet 3.1/4.0,够用
MySQL5.7 / 8.0二选一,驱动类名不同
mysql-connector-java5.1.49 或 8.0.x与 MySQL 版本对应
本地管理工具Navicat / DBeaver / IDEA 自带只用来导数据,不参与运行

要知道 JSP 页面能跑起来,靠的是 Tomcat 这个 Servlet 容器。你改了 JSP 文件,Tomcat 会自动重新编译,不需要重启,这算 JSP 项目的便利之处。但改 Java 类就必须重新编译并部署,很多新手死磕在这里:页面改了没反应,其实是 .class 没更新。

3.2 导入数据库脚本:命令行导入比图形工具更稳

导入 SQL 脚本这一步,我用命令行多于图形工具,原因在后文避坑章节细说。先在 MySQL 里建库并导入脚本:

mysql -u root -p < pet_clinic.sql

如果脚本里没有 CREATE DATABASE 语句,就先手动建库再导入:

mysql -u root -p -e "CREATE DATABASE pet_clinic DEFAULT CHARACTER SET utf8mb4;" mysql -u root -p pet_clinic < pet_clinic.sql

这里的参数含义分别是:-u 指定用户名,-p 提示输入密码,-e 执行一段 SQL 而不进入交互界面,最后一个 pet_clinic 是目标数据库名。导入成功后,用 show tables 验证表是否齐全:

mysql -u root -p pet_clinic -e "SHOW TABLES;"

只要能看到 pet_owner、pet、medical_record 等表,数据库这关就算过了。这里有个常见坑:如果脚本里用了 DELIMITER 或触发器,图形界面导入经常失败,命令行反而没事。导入后顺手查一下记录数,确认初始数据有进去,别到时候网页列表空空的还以为是代码问题。

3.3 改 JDBC 连接配置:四个参数一处都不能错

数据库脚本导好了,下一步就是把 JSP 项目和数据库对接上。几乎所有课程设计都有一个 DBUtil 或 DBConnection 类,集中管理连接。找到它,改成你自己的数据库名、用户名、密码。下面是最常见的连接代码形态:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/pet_clinic?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false"; private static final String USER = "root"; private static final String PASSWORD = "你的密码"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }

四个参数逐一说明。DRIVER 是驱动类名,MySQL 5.x 用 com.mysql.jdbc.Driver,MySQL 8.x 必须用 com.mysql.cj.jdbc.Driver。URL 中的 localhost:3306 是数据库地址和端口,pet_clinic 是库名,后面的 useUnicode 和 characterEncoding 控制中文不乱码,serverTimezone 是 MySQL 8 连 JDK 8 必须加的,否则报时区错误,useSSL=false 是本地开发关掉加密握手,省得告警噪音。USER 和 PASSWORD 就用你本机 MySQL 的账号,别用源码包里现成的,那基本对不上。

改完连接信息后编译部署。有 IDE 就用 IDE 的 Tomcat 集成功能,没有就把整个项目目录拷到 Tomcat 的 webapps 下,启动 Tomcat 让它自动部署。注意项目目录名就是访问路径,比如目录叫 PetClinic,访问地址就是 http://localhost:8080/PetClinic/,这个细节放到验证环节说。

3.4 从浏览器到控制台的验证链路:一次完整的登录

启动 Tomcat 的方式,Windows 下双击 startup.bat,Linux/Mac 执行 startup.sh。启动后先看控制台有没有“Server startup”字样,有就说明容器起来了。接着访问 http://localhost:8080/项目名/index.jsp,页面能开,说明 Tomcat 这一层通了;输入账号密码点登录,能跳转,说明数据库那一层也通了。

这时要会看日志。Tomcat 日志在 logs/catalina.out(Linux/Mac)或 logs/catalina.yyyy-MM-dd.log(Windows 按天滚动),报错堆栈全在里面。常见情况是页面 500,浏览器只显示一行报错,真正的异常原因在日志第二屏。我习惯打开日志文件,Ctrl+F 搜“Caused by”,一层层剥到最底层的异常,那才是根因。

提示:改完 Java 代码务必重启 Tomcat 或执行重新部署,只刷新浏览器不会重新编译 Java 类。JSP 文件可以热更新,Java 类不行。这是新手最容易翻车的地方。

验证完登录,整个系统就算立住了。但立住只是第一步,下一步才是真正考验内功的:改业务逻辑。

4. 改业务前的三件事:宠物档案展示、去重统计与 SQL 注入防护

4.1 宠物信息展示页:图片路径和坐标定位是高频改造点

很多宠物诊所系统的首页是宠物列表,点进去看详情。图片这块课程设计基本用两种方案:要么图片存本地磁盘,数据库只存路径;要么把图片转成 base64 直接塞进数据库字段。我强烈推荐第一种,因为 base64 会把数据库撑大,而且 JSP 页面渲染时会卡。路径方案里有个细节:photo_path 存的是“相对路径”,比如 /upload/pet1.jpg,JSP 用 ${pageContext.request.contextPath} 拼接根路径才能正确显示。

<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <div class="pet-card"> <img src="${pageContext.request.contextPath}${pet.photoPath}" alt="${pet.petName}" style="width: 300px; height: 200px; object-fit: cover;" /> <h3>${pet.petName} (${pet.species})</h3> <p>主人:${pet.ownerName} 电话:${pet.ownerPhone}</p> </div>

这里 ${pageContext.request.contextPath} 是 JSP EL 表达式,作用是把项目上下文路径拼到图片地址前面,防止部署路径变化后图片全部 404。object-fit: cover 保证图片不变形裁剪,这在头像展示里很常用。photoPath 字段如果存的是“/upload/pet1.jpg”这种绝对路径形式,拼上上下文路径就直接能用;如果存的是“upload/pet1.jpg”,前面少了斜杠,浏览器解析时会相对当前页面路径寻找,很容易 404。

图片坐标定位这个需求,常见场景是在宠物照片上标记病灶位置,比如皮肤病部位。做法是用 CSS 把图片套在 div 里,监听鼠标点击事件,把点击坐标换算成图片内相对坐标,再把坐标值放进隐藏字段提交。这个功能不复杂,但很体现细节。代码如下:

<div style="position: relative; display: inline-block;"> <img id="petPhoto" src="${pageContext.request.contextPath}${pet.photoPath}" style="width: 400px; height: 300px;" /> <input type="hidden" id="markX" name="markX" value="" /> <input type="hidden" id="markY" name="markY" value="" /> <div id="marker" style="display:none; position:absolute; border:2px solid red; width:20px; height:20px; pointer-events:none;"></div> </div> <script> document.getElementById('petPhoto').addEventListener('click', function(e) { var rect = this.getBoundingClientRect(); var x = Math.round(e.clientX - rect.left); var y = Math.round(e.clientY - rect.top); document.getElementById('markX').value = x; document.getElementById('markY').value = y; var marker = document.getElementById('marker'); marker.style.left = x + 'px'; marker.style.top = y + 'px'; marker.style.display = 'block'; }); </script>

这段代码的核心是 getBoundingClientRect(),它拿到图片左上角相对视口的位置,再用鼠标点击坐标减去它,就得到图片内部的相对坐标。这个坐标不随页面滚动而偏移,是图片标注的基准。标记红框用绝对定位贴在图片容器里,pointer-events: none 是为了让红框不遮挡鼠标事件。后端收到 markX/markY 两个字段后,存进数据库或直接做后续判断。

4.2 就诊记录查询优化:同一个宠物重复挂号怎么去重

诊所系统里最常见的查询是“这只宠物来过几次、每次诊断是什么”。但课程设计的数据经常有重复,比如同一天挂两次号、同一诊断写了两条记录。做统计前不去重,前端列表会看到一堆重复行。SQL 去重三种手段:DISTINCT 用于整行去重,GROUP BY 用于分组统计,ROW_NUMBER() 用于按业务规则去重。

-- 场景1:统计每个宠物就诊次数 SELECT pet_id, COUNT(*) AS visit_count FROM medical_record GROUP BY pet_id ORDER BY visit_count DESC; -- 场景2:同一宠物同一天只算一次就诊 SELECT pet_id, DATE(visit_date), COUNT(DISTINCT DATE(visit_date)) AS actual_visits FROM medical_record GROUP BY pet_id; -- 场景3:取出每个宠物最新一条就诊记录 SELECT r.* FROM ( SELECT record_id, pet_id, diagnosis, visit_date, ROW_NUMBER() OVER (PARTITION BY pet_id ORDER BY visit_date DESC) AS rn FROM medical_record ) r WHERE r.rn = 1;

三段 SQL 分别演示了统计总数、按天去重、取最新记录三种场景。第二段里的 COUNT(DISTINCT DATE(visit_date)) 是去重统计的关键,把 DATETIME 转成 DATE 再计数,同一天多条只算一次。第三段的窗口函数 ROW_NUMBER() 是 MySQL 8.0 才有的特性,5.7 跑不了,老版本得改成“先 ORDER BY 再 GROUP BY”的子查询方案。这里提示一下:课程设计大多用 MySQL 5.7,如果窗口函数报语法错,别硬调 SQL,先确认数据库版本。

慢 SQL 的问题也集中在这种统计查询上。pet_id 和 visit_date 如果没建索引,数据量上百条时感觉不出来,上千条就开始卡页面。我一般会在外键字段和经常做 WHERE 过滤的字段上补索引:

ALTER TABLE medical_record ADD INDEX idx_pet_id (pet_id); ALTER TABLE medical_record ADD INDEX idx_visit_date (visit_date);

加了索引之后,用 EXPLAIN SELECT 验证一下优化效果。EXPLAIN 输出里的 type 列如果从 ALL 变成 ref 或 range,说明索引生效了。这一步是区分“能跑”和“能用”的分水岭,课程设计答辩时老师也爱问这个,答上来是加分项。

4.3 把拼字符串的 SQL 改成 PreparedStatement:顺手堵住注入

课程设计源码里最常见的隐患,是登录功能用字符串拼接 SQL。这种代码不仅丑,而且是一个标准的 SQL 注入入口。很多老教材还在教这种写法,但放到今天就是给自己埋雷。看下面的反面例子:

SELECT * FROM user WHERE username = 'admin' AND password = '123456'

如果用户名输入的是 admin' -- ,拼接后变成:

SELECT * FROM user WHERE username = 'admin' -- ' AND password = '123456'

-- 把后面的条件注释掉了,等于只用用户名登录。这种万能密码绕过方式在靶场里天天上演,放到真实系统里就是灾难。改造方式很简单,交给 PreparedStatement 参数化:

PreparedStatement ps = conn.prepareStatement( "SELECT * FROM user WHERE username = ? AND password = ?"); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery();

参数化的原理是:预编译阶段把 SQL 结构固定下来,用户输入只作为参数值传入,而不是拼进 SQL 语句本身。这样即使输入里带单引号和注释符,数据库也只会把它当成一个普通的字符串值,不会改变查询结构。这是防御 SQL 注入最基础也最有效的手段。

我接手过的课程设计里,十个有八个登录代码是拼字符串的,改起来成本不高但对系统安全性提升巨大。改造时要注意 setString 的下标从 1 开始,不是从 0 开始,这个细节经常写错。另外,如果涉及模糊查询 like,写法是 ? 对应 "%" + keyword + "%",前后拼接放在参数上,不在 SQL 里拼:

PreparedStatement ps = conn.prepareStatement( "SELECT * FROM pet WHERE pet_name LIKE ?"); ps.setString(1, "%" + keyword + "%");

这里参数值里拼了 %,但 SQL 结构保持完整,注入风险可控。把项目里所有 Statement.createStatement() 改成 PreparedStatement,并配合 executeQuery() 调用,安全这块就算补上了。

5. 常见问题排查:连不上数据库、中文乱码与驱动报错

这一章是血泪经验集中区。JSP 项目跑不起来,翻来覆去就是那几个原因,每条按“现象 → 原因 → 解决”的顺序说清楚。

5.1 现象:页面报 500,日志里有 ClassNotFoundException: com.mysql.jdbc.Driver

原因有两个:一是驱动 jar 没放进 WEB-INF/lib,二是 MySQL 版本和驱动类名不匹配。MySQL 5.x 用 com.mysql.jdbc.Driver,MySQL 8.x 必须用 com.mysql.cj.jdbc.Driver。很多课程设计源码基于老环境写的,你本地是 MySQL 8.0,类名对不上自然加载失败。

解决:先看 WEB-INF/lib 下有没有 mysql-connector 的 jar,没有就去下载对应版本的驱动放进去。然后确认驱动类名和 MySQL 版本匹配,8.0 环境把代码里的 Class.forName("com.mysql.jdbc.Driver") 改成 Class.forName("com.mysql.cj.jdbc.Driver")。改完重启 Tomcat 再试。

5.2 现象:页面上中文正常,插入数据库后变成问号或乱码

原因:连接 URL 没加 characterEncoding 参数,或数据库、表、页面三处字符集不一致。JSP 页面本身是 UTF-8,数据库是 latin1,连接时没指定编码,MySQL 就会按默认字符集转码,中文就变成“???”。

解决:三处统一。数据库建库用 utf8mb4;连接 URL 加 useUnicode=true&characterEncoding=UTF-8;JSP 页面头部加 <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>。这样改完再插入中文,乱码基本痊愈。如果之前已经插入了乱码数据,改完编码后旧数据还是坏的,需要清掉重插,没有后悔药。

5.3 现象:启动时 MySQL 8 报 InvalidConnectionAttributeException,时区是乱码

原因:MySQL 8.0 的连接驱动强制要求指定 serverTimezone 参数,而 JVM 默认时区和中国时区不一致。报错里那串乱码就是 Ubuntu 系统时区名,不是真的乱码,是编码没对上。

解决:在 JDBC URL 末尾追加 serverTimezone=Asia/Shanghai,或者用 serverTimezone=GMT%2B8。注意“+”号在 URL 里要转义成 %2B,直接用 + 号在某些解析器里会被当成空格。这是新手最容易忽略的细节,复制官方示例时经常踩。

5.4 现象:系统前一天还好好的,第二天第一次访问特别慢或报 Communications link failure

原因:MySQL 的 wait_timeout 默认 8 小时,连接空闲超过 8 小时会被服务端断开,但客户端连接池不知道,还在用失效连接。

解决:在连接池配置里加三个参数:testWhileIdle=true、timeBetweenEvictionRunsMillis=60000、validationQuery=SELECT 1。这三个参数让连接池定时检查空闲连接是否还活着,发现断开的就丢掉重建。如果没有用连接池,而是每次直接 DriverManager.getConnection,就不会遇到这个问题,因为每次都是新建连接。这也是我在后面章节推荐连接池的原因之一。

5.5 现象:用图形工具导入 SQL 脚本报 1064 语法错误,命令行却能成功

原因:图形工具的字符集设置和脚本不一致,或者脚本里有触发器、存储过程用到了 DELIMITER 语法,图形工具没正确处理。还有一种是脚本本身带 BOM 头,工具把 BOM 当成了 SQL 的一部分。

解决:优先用命令行导入。如果必须用图形工具,导入前把脚本用记事本另存为 UTF-8 无 BOM 格式,并在导入设置里选对字符集。遇到 DELIMITER 报错,把存储过程或触发器部分单独复制出来,连 DELIMITER 一起在命令行执行。

提示:排查问题先看底层异常。浏览器显示的报错是表层的,打开 Tomcat 日志搜“Caused by”,一层层往下找,最后一层才是真凶。很多时候前面包了三四层空指针或 IO 异常,都是假象。

6. 从能跑到能用:给这个小系统补上连接池与幂等处理

6.1 用连接池替换 DriverManager:性能和稳定性同时提升

DriverManager 每次 getConnection 都走 TCP 握手,频繁访问时开销全耗在连接建立上。常见做法是引入 DBCP 或 c3p0 连接池,把连接复用起来。用 DBCP 只需要在 DBUtil 里换一段配置:

import org.apache.commons.dbcp2.BasicDataSource; public class DBUtil { private static final BasicDataSource dataSource = new BasicDataSource(); static { dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/pet_clinic?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai"); dataSource.setUsername("root"); dataSource.setPassword("你的密码"); dataSource.setInitialSize(5); dataSource.setMaxTotal(20); dataSource.setMaxIdle(10); dataSource.setTestWhileIdle(true); dataSource.setTimeBetweenEvictionRunsMillis(60000); dataSource.setValidationQuery("SELECT 1"); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }

initialSize 是启动时预建的连接数,maxTotal 是池上限,maxIdle 是空闲保留数。这几个参数按项目并发量调,课程设计 5/20/10 足够。testWhileIdle 配合 validationQuery 就是解决 8 小时断连的关键。

6.2 表单重复提交:用重定向而不是“刷新一次”

JSP 里经常有人问“页面加载完后刷新一次”,实际业务场景往往是提交后刷新导致重复插入。刷新浏览器重发 POST 请求,就诊记录就会多一条。解决办法不是让页面自动刷新,而是 Redirect-After-POST:处理完写入操作后重定向到查询页。

response.sendRedirect(request.getContextPath() + "/petList.jsp");

重定向后浏览器发的是 GET 请求,刷新不会重复提交。这个模式顺手也解决了“列表页看不到新增数据”的问题,因为重定向后页面重新从数据库拉数据。把写操作和读操作分开,是区分新手和熟手的一条分界线。

6.3 验证改造效果:EXPLAIN 和断线重测

改完连接池和防重复提交,用两个手段验证。一是对慢查询跑 EXPLAIN,确认走索引而不是全表扫描。二是把 MySQL 的 wait_timeout 临时改成 60 秒,等一分钟再访问页面,看是否还能正常拿到数据。第二个验证能直接暴露连接池配置有没有生效。

我接手过好几个课程设计,最大教训是:项目能跑是一回事,禁不禁得起重启和隔天再用是另一回事。数据库编码、驱动版本、连接池这三个点,任何一处没对齐,都会在某个深夜突然翻车。你把这个系统跑通后,建议花半天把这三处全部理顺,再顺手给登录加个 PreparedStatement。这套流程走完,JSP 项目的基本功就算立住了,希望帮到你。

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

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

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

立即咨询