JSP+MySQL学生宿舍管理系统开发:数据库设计、连接池与部署排错实战
2026/9/13 14:00:35 网站建设 项目流程

简介:这是一份基于JSP+MySQL的学生宿舍管理系统完整实训作业包,面向高校软件技术、计算机相关专业学生及Java Web入门开发者,解决宿舍管理课程设计或实训项目缺乏完整可运行代码的问题。资源共67个文件,包含17个Java源文件、17个编译后的class文件、10个JSP页面、8个XML配置、7个JAR依赖库、SQL数据库脚本和Word作业文档等,压缩包仅5.55MB,结构清晰、便于按需取用。核心功能覆盖学生信息管理、宿舍分配与调整、住宿费用管理、在线报修维修、统计报表和用户权限管理,基本串起JSP+Servlet+MySQL的典型开发链路。内置的SQL初始化脚本可一键初始化数据库,作业文档中另有系统架构、数据库设计及配置步骤说明,大幅降低复现门槛。目前已有69人学习下载,适合作为课程设计参考、实训报告配套源码或初学Java Web时练习综合项目开发的样板。

1. 实训作业里最容易被问倒的不是写代码,是连不上数据库

做JSP+MySQL的学生宿舍管理系统,大多数同学卡住的地方不是功能没写完,而是从“代码能编译”到“Tomcat里能跑通”之间的那段路。课程设计或实训作业通常要求交付三样东西:源代码、数据库脚本、说明文档,但评分时老师打开项目先看的不一定是界面有多花哨,而是你能不能当场把项目跑起来、能不能解释清楚request.getParameter之后数据经历了什么。这套系统的业务本身并不复杂:楼栋、宿舍、学生、入住、退宿、报修、访客、水电费记录,属于典型的管理信息系统CRUD。真正区分及格和优秀的分水岭,在于你是否理解了三层结构里JSP、Servlet、DAO各自的职责,以及MySQL连接串里那串useSSL、serverTimezone参数为什么不能删。

顺着“基于JSP+MySQL”这个标题往下拆,你会发现它等价于一套完整的Web开发基本功训练:JDBC连接管理、连接池参数调优、JSP的page指令和taglib引入、Servlet跳转与session控制、数据库外键设计、以及最后的部署路径检查。我一般会把这类项目当作一条“最小可运行的Java Web生产线”来复现:建库、建表、写工具类、写DAO、写Servlet、写JSP、配置Tomcat、部署、排错。这篇博文按实战顺序展开,每一步都有可以直接抄走的代码和参数表,最后收在几个只有动手跑过才会碰到的细节上。

2. 宿舍管理系统的数据模型:从需求到MySQL建表SQL

2.1 先划分业务边界,别一上来就写建表语句

学生宿舍管理系统的核心业务围绕“宿舍资源”和“学生住宿”展开,常见的功能模块有系统登录、楼栋管理、宿舍管理、学生管理、入住分配、退宿处理、来访登记、报修管理、水电费记录。实训作业的评分标准里,功能完整度是一方面,数据库设计的规范性是另一方面。很多人为了省事,把学生姓名、宿舍号、报修内容全部塞进一张大表里,导致很多冗余字段,后面写统计SQL时要到处distinct或者group by一堆无关列。更合理的做法是先按业务对象拆表,再按关系建外键。

每张表的主键建议用自增id;如果是纯粹给实训评分用的项目,不需要引入雪花算法或分布式主键。宿舍表和楼栋表是主从关系,学生表和宿舍表是多对一关系,报修表、访客表、水电费表都以学生或宿舍作为外键来源。之所以不建议在实训项目里把所有关联都加物理外键,是因为你后期往表里插测试数据、批量导入Excel时会频繁碰到外键约束卡插入顺序的问题;但完全不加外键又解释不通“合理性”。我一般的做法是:在表结构上保留外键字段并在设计文档里画好ER图,同时把物理外键加上,但只要在代码里把级联和删除策略想清楚,就不会被约束绊住。

2.2 建成5张核心表,覆盖实训评分的基本功能点

下面这套建表SQL覆盖了登录、楼栋、宿舍、学生、报修、水电费六个功能点,其中登录账号我单独抽了一张sys_user表,不和学生表混在一起。这样做的原因是admin账号和普通学生的信息字段完全不同,硬塞进同一张表会导致大量列为空。

CREATE DATABASE IF NOT EXISTS dorm DEFAULT CHARSET utf8mb4; USE dorm; CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL COMMENT '使用MD5加密后存储', real_name VARCHAR(50), role TINYINT DEFAULT 2 COMMENT '1管理员 2宿管 3学生', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB; CREATE TABLE building ( id INT PRIMARY KEY AUTO_INCREMENT, building_no VARCHAR(20) NOT NULL, floor_count INT DEFAULT 6, room_count INT DEFAULT 60, manager VARCHAR(50) ) ENGINE=InnoDB; CREATE TABLE dorm_room ( id INT PRIMARY KEY AUTO_INCREMENT, building_id INT NOT NULL, room_no VARCHAR(20) NOT NULL, bed_count INT DEFAULT 4, used_bed_count INT DEFAULT 0, tel VARCHAR(20), KEY idx_building (building_id), CONSTRAINT fk_room_building FOREIGN KEY (building_id) REFERENCES building(id) ) ENGINE=InnoDB; CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, student_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, gender CHAR(1), college VARCHAR(50), major VARCHAR(50), phone VARCHAR(20), dorm_room_id INT, bed_index TINYINT COMMENT '1-4,标识床位号', status TINYINT DEFAULT 1 COMMENT '1在住 0退宿', KEY idx_dorm (dorm_room_id), CONSTRAINT fk_student_room FOREIGN KEY (dorm_room_id) REFERENCES dorm_room(id) ) ENGINE=InnoDB; CREATE TABLE repair ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL, dorm_room_id INT NOT NULL, content VARCHAR(255) NOT NULL, status TINYINT DEFAULT 0 COMMENT '0待处理 1处理中 2已完成', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, finish_time DATETIME, KEY idx_status (status) ) ENGINE=InnoDB;

建表SQL拆成两层来看:第一层是主表(building、dorm_room、student),它们决定了系统里最核心的“人在哪里住”;第二层是业务表(repair、water_electric),它们依赖前面的主表生成新的流水数据。CHARSET选了utf8mb4而不是utf8,是因为如果学生姓名里出现生僻字或者emoji,utf8mb3在MySQL 5.7以上版本会报“Incorrect string value”错误,这个坑在实训演示现场非常常见。ENGINE统一用InnoDB,保证事务和外键支持。KEY idx_status (status)这行是给常用查询字段建单列索引,状态筛选在报修列表里几乎每次都会用,不加索引的话数据量上千后排序和筛选会有明显卡顿。

2.3 给表加索引的优先级:按查询习惯来,不按字段多少来

很多实训文档里写“索引越多越好”,这句话对MySQL是完全错误的。索引会加速查询,但会拖慢insert和update,因为每次写操作都要同步维护索引树。宿舍管理系统里最常用的查询场景是:学生列表按学生姓名模糊搜索、宿舍查询按楼栋和房间号精确匹配、报修列表按状态筛选。针对这三种场景,索引策略就明确了:student表的student_no用唯一索引,name字段用普通索引(实际使用LIKE 'keyword%'时能命中索引)、status这种低基数字段不适合单独建索引,但和create_time组合成联合索引时可以用于“待处理报修按时间排序”的查询。

在Navicat里导入脚本后,可以用SHOW INDEX FROM student;查看当前表上的索引,注意看Cardinality数值,这个值越接近实际行数,说明索引区分度越好。MySQL安装配置教程里通常不会讲这一步,但课程设计文档里如果能写清“哪些索引是根据哪条业务SQL设计的”,得分会比堆一堆KEY要高。

3. 从JDBC到JSP落地:连接池参数、DAO模式与JSP页面取值

3.1 连接管理别用DriverManager裸连,直接上连接池

实训项目里最常见的写法是在每个DAO类里写Class.forName("com.mysql.jdbc.Driver")然后DriverManager.getConnection(url, user, password),再在finally里关闭连接。这个写法能跑,但有两个问题。第一,com.mysql.jdbc.Driver在MySQL 8.x的jdbc驱动里已经被标记为过时,新驱动类名是com.mysql.cj.jdbc.Driver,同时连接串里必须加serverTimezoneuseSSL=false,否则会报时区错误和SSL告警。第二,每个请求都新建物理连接,伸手党式地从连接池里取一个现成的连接,性能完全不同。实训演示时如果同时开着多个页面,或者用脚本快速刷新,裸连方式很容易把数据库的连接数打满。

更稳妥的方案是用Apache DBCP或者阿里的Druid做连接池,在webapp/WEB-INF/web.xml里配置Resource并通过JNDI获取数据源。但考虑到很多实训环境用的是Tomcat 8/9,直接在项目里用Druid的jar包配合一个工具类读取配置的方式,依赖更少、更好解释。

public class DBHelper { private static DruidDataSource dataSource; static { try { Properties props = new Properties(); props.load(DBHelper.class.getClassLoader().getResourceAsStream("db.properties")); dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(props); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { } } if (ps != null) { try { ps.close(); } catch (SQLException e) { } } if (conn != null) { try { conn.close(); } catch (SQLException e) { } } } }

这段代码里最关键的是DruidDataSourceFactory.createDataSource(props),它会把properties文件里的配置直接映射到连接池对象上,不需要手动一个个set。db.properties里几个必调参数如下:

driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/dorm?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username=root password=123456 initialSize=5 maxActive=20 maxWait=60000 validationQuery=SELECT 1 testWhileIdle=true

allowPublicKeyRetrieval这个参数只有在MySQL 8.x的caching_sha2_password认证插件下才需要,如果你用的MySQL是5.7或更早版本,这个参数不写也没事。initialSize设5就够了,不要为了“看起来性能好”设成50,连接池的启动时间和占用的数据库连接数都会增加,实训评分机器的内存往往不大,很容易直接把MySQL拖慢。maxWait=60000表示从连接池获取连接时最多等60秒,如果60秒内拿不到连接就抛异常,这样至少能让你从异常栈里看到“wait millis”相关日志,而不是让请求无限挂起。

3.2 DAO层只做数据访问,别把业务逻辑塞进JDBC方法里

JSP+MySQL的宿舍管理系统,代码组织上最容易被扣分的地方是JSP页面里直接写了一堆<% %>脚本片段,里面又套着JDBC查询逻辑。这种写法在开发初期很快,但页面稍微复杂一点,HTML标签和Java代码混在一起,后面改一个字段要翻几百行,而且报错时Tomcat只会告诉你这一行编译失败,不会告诉你是什么业务逻辑错了。

按实训评分标准的套路,正确做法是:JSP只负责展示数据,Servlet接收请求并调用Service/DAO层,DAO层只负责SQL操作。关于要不要再套一层Service,这个没有硬性规定,但为了答辩时好讲,我建议至少把“查询某栋楼的空闲宿舍”这类规则写在DAO方法里而不是写在JSP里。

public class StudentDAO { public List<Student> findByCondition(String keyword, int page, int pageSize) { List<Student> list = new ArrayList<>(); StringBuilder sql = new StringBuilder("SELECT * FROM student WHERE 1=1 "); List<Object> params = new ArrayList<>(); if (keyword != null && !keyword.trim().isEmpty()) { sql.append("AND name LIKE ? "); params.add("%" + keyword.trim() + "%"); } sql.append("ORDER BY id DESC LIMIT ?, ?"); params.add((page - 1) * pageSize); params.add(pageSize); try (Connection conn = DBHelper.getConnection(); PreparedStatement ps = conn.prepareStatement(sql.toString())) { for (int i = 0; i < params.size(); i++) { ps.setObject(i + 1, params.get(i)); } try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { Student stu = new Student(); stu.setId(rs.getInt("id")); stu.setName(rs.getString("name")); stu.setStudentNo(rs.getString("student_no")); stu.setDormRoomId(rs.getInt("dorm_room_id")); stu.setStatus(rs.getInt("status")); list.add(stu); } } } catch (SQLException e) { e.printStackTrace(); } return list; } }

这段代码里有两个容易被忽略的细节。第一个是使用了LIMIT ?, ?,这是MySQL的分页写法,第一个问号是偏移量(page-1)*pageSize,第二个问号是每页条数。如果数据库换成Oracle或SQL Server,这个SQL语法就不能用,实训答辩时老师常问“你的分页SQL在Oracle里能跑吗”,这就是考察点。第二个是PreparedStatement的参数下标从1开始,而Java的List下标从0开始,所以ps.setObject(i + 1, ...)容易写错,建议自己写分页查询时把参数列表用一个List统一管理,下标偏移一目了然。

3.3 JSP页面用JSTL和EL表达式,循环拼接是死路

写完DAO之后,剩下的页面展示问题就是JSP模板技术。现在再回头用<%= %>去渲染表格行确实已经过时了。规范做法是引入JSTL标签库,用<c:forEach>循环表格行,用${student.name}取数据。

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <body> <table border="1"> <tr> <th>学号</th> <th>姓名</th> <th>宿舍</th> <th>状态</th> </tr> <c:forEach items="${pageData.list}" var="stu"> <tr> <td>${stu.studentNo}</td> <td>${stu.name}</td> <td>${stu.dormRoomId}</td> <td> <c:choose> <c:when test="${stu.status == 1}">在住</c:when> <c:otherwise>退宿</c:otherwise> </c:choose> </td> </tr> </c:forEach> </table> </body> </html>

核心的坑在于前缀。<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>这行必须原样写对,很多人从旧项目里复制过来,uri写的是http://java.sun.com/jstl/core,少了/jsp路径,启动后页面报“Unable to find taglib”错误。另外一个容易踩的是items="${pageData.list}"的取值路径,pageData是Servlet里request.setAttribute("pageData", data)设定的对象,list是其中存放的分页列表字段。如果属性名对不上,JSP页面不会直接报错,只会输出空表格,经验不足的同学往往会怀疑Java代码写错了。

JSP个人信息展示页面在这个项目里就是一个独立的小页面,显示当前登录用户的账号、姓名、角色、最近登录时间。设计上不要用session.getAttribute直接输到页面上,而是通过一个<jsp:useBean>或者直接把用户对象塞进request里再配合EL表达式取值,这样页面代码更干净。如果是Eclipse或IDEA里部署的Web项目,可以查看Tomcat的工作目录,jsp编译class文件保存在哪里这个热搜问题的答案是:work/Catalina/localhost/项目名/org/apache/jsp/,JSP页面第一次被访问时会在这里被编译成Java源文件和class文件。遇到页面显示500错误时,去这个目录看一眼对应的_class文件的内容,能快速定位是标签库没引对还是EL表达式取值为空。

4. 数据库连接、中文乱码与浏览器离开页面提示的三连坑

4.1 MySQL 8.x安装配置时先确认驱动和URL,再写代码

mysql安装配置教程很多,但宿舍管理系统这种老牌JSP项目常见的环境组合是:JDK 1.8 + Tomcat 8.5 + MySQL 5.7或8.0。如果你是网络安全或软件工程专业做课程设计,很可能老师给的旧代码里写的是com.mysql.jdbc.Driver,而你的机器装的是MySQL 8,这时候启动项目会直接报ClassNotFoundException。处理办法很简单:换成com.mysql.cj.jdbc.Driver,并引入mysql-connector-java 8.x版本的jar包。

如果是选择MySQL官网下载最新版8.x,安装完成后记得在命令行工具里用mysql -u root -p验证能否正常登录,并执行一次SELECT VERSION();。比较常见的问题是安装时选的是“记住密码”而不是“设置密码”,或者安装过程中指定了密码但连接串里没写对。在IDEA里跑Main方法测试JDBC连接时不通过,先不要急着怀疑代码,直接点击IDEA右侧的Database面板,用同样的url和账号密码测试一下,如果那里也连不上,问题就在MySQL服务端或网络配置,不在你的Java代码里。

4.2 中文乱码要从URL、请求、响应三个方向一起堵

JSP项目里的中文乱码几乎都是“三处不一致”引起的:页面本身的编码、HTTP请求的编码、数据库连接的编码。页面编码在JSP第一行用<%@ page contentType="text/html;charset=UTF-8" language="java" %>来控制,注意这个page指令必须写在JSP文件的最顶部,前面不能有任何空行或HTML标签。如果页面输出正常但插入数据库后变问号,那问题在JDBC连接串里的characterEncoding=UTF-8参数,以及建表时用的字符集。

MySQL的连接url里同时存在useUnicode=truecharacterEncoding=UTF-8两个参数时,驱动会按后者指定的字符集处理请求和响应的编码。如果建表时某些表漏写了DEFAULT CHARSET=utf8mb4,用ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4;临时转一下也行,但如果表里已经有乱码数据,转换并不会自动修复已存在的乱码,必须先把乱码数据删掉或重置。

如果是表单提交后Servlcet里拿到的中文参数乱码,确认你的Tomcat版本。Tomcat 8及以上版本默认使用UTF-8处理POST请求体,但GET请求的query string默认按ISO-8859-1解析,所以中文姓名通过GET方式传参乱码时,需要给tomcat的server.xml里的Connector节点加上URIEncoding="UTF-8"属性。这个细节很多人不知道,因为POST请求在JSP实训项目里更常见,GET搜索功能往往被忽略。我的习惯是写一个EncodingFilter,在doFilter里统一设置request.setCharacterEncoding("UTF-8")response.setCharacterEncoding("UTF-8"),这样至少能覆盖表单POST提交的情况。

4.3 屏蔽jsp离开页面提示,是浏览器策略不是代码问题

热词里有一条“屏蔽jsp离开页面提示”,这个场景和宿舍管理系统里的“正在填写报修单”很接近。当JSP页面注册了beforeunload事件时,浏览器会在用户点击导航链接或关闭页面时弹出“确定要离开此页面吗”的系统对话框,用来防止表单内容丢失。

window.addEventListener('beforeunload', function (e) { var content = document.getElementById('repairContent').value; if (content.trim() !== '') { e.preventDefault(); e.returnValue = ''; } });

这段代码的逻辑是:只有当报修内容的文本框非空时才拦截离开动作,空表单直接放行。e.returnValue = ''是兼容老版本浏览器的写法,现在大多数现代浏览器已经忽略了提示文案,只保留默认的固定文本。如果你的页面怎么点都弹这个提示,问题通常出在beforeunload绑定后没有在表单提交时解绑,比如用户已经点“提交”按钮了,但事件监听器还存在,导致提交按钮本身也触发了离开页面的拦截逻辑。解决办法是给form的onsubmit加一个标记位,让beforeunload里检测到isSubmitting为true时直接return不弹窗。

这个细节很适合在实训文档里写成“项目难点”,因为老师看到你主动解决了用户体验问题,而不是只会调数据库,印象分会不一样。

5. JSP项目里的Tomcat部署检查、断点命中与class文件的实际位置

5.1 把项目挂到Tomcat的webapps下,启动后先看三个日志

宿舍管理系统在实训验收时要当场在浏览器里跑起来,所以部署环节一定要熟练。在IDEA里点Run按钮启动Tomcat是最快捷的方式,但有些机房机器没有配置IDEA的Tomcat插件,或者教室电脑只有Eclipse,这时候就需要手动部署。手动部署的做法:把项目导出成war包,放到Tomcat安装目录的webapps文件夹下,然后执行bin/startup.bat(Windows)或bin/startup.sh(Linux)。启动后不要急着开浏览器,先看三个日志文件:logs/catalina.outlogs/catalina.日期.loglogs/localhost.日期.loglogs/manager.日期.log

启动报错时,最常见的提示是ClassNotFoundExceptionNoClassDefFoundError,这通常意味着项目里用到的jar包没有打进WEB-INF/lib目录。网络上很多人喜欢把mysql-connector.jar放在Tomcat的lib目录下,这样做Tomcat启动不会报错,但如果你之后换一台机器部署,忘了把这个共享jar包一起拷过去,新环境就起不来了。我把项目的数据库驱动jar包固定放在webapp/WEB-INF/lib/目录下,随项目一起走。

5.2 当前不会命中断点:源码与部署class不一致时的自检路径

用IDEA启动Tomcat调试时,有时候打了断点却出现“当前不会命中断点”的提示,尤其是JSP页面对应的Java类。这个问题的原因和IDEA的编译输出路径有关:JSP页面在运行时才被Tomcat动态编译成class,而IDEA的断点是对ide编译好的目标类生效的,两者来源不同,所以命不中。处理办法是改用JSP调试插件或者直接在JSP文件里打印日志到Tomcat的logs目录,而不是死磕断点。

对于Servlet类和DAO类来说,如果也出现“当前不会命中断点”,需要检查项目里是否存在两个相同路径的class文件。Tomcat的work目录下会输出JSP编译的class,但Servlet和业务类的class是从WEB-INF/classes加载的。如果你的项目配置文件里有多个source directory,并且编译输出到了不同位置,IDEA可能调试的是其中一份,而Tomcat加载的是另一份。用javap -c看下class文件路径,或者直接在IDEA里Ctrl+Shift+F9重新编译该模块,一般能解决。这个知识点很适合写进数据库课程设计的答辩文档里,属于真正的“实训踩坑记录”。

5.3 MySQL workbench使用教程里的反向工程,可以拿来生成文档

如果实训报告里要画ER图,用MySQL Workbench的Database菜单里的Reverse Engineer功能可以直接从现成的数据库导出ER图。操作步骤是:连接数据库,选择数据库,然后执行逆向工程,工具会生成所有表的外键关系图,直接保存成图片放到课程设计文档里。这里的坑在于:如果建表时没有给外键命名或者外键类型不一致,逆向工程生成的连线会比预期少,所以在可视化之前先确认表名是以复数还是单数命名,以及外键字段和引用字段的数据类型是否完全一致,比如INT UNSIGNEDINT就不能兼容。

数据库脚本的管理可以顺手用一下mysqldump导出热备份,命令是:

mysqldump -u root -p --default-character-set=utf8mb4 --databases dorm > dorm_backup.sql

这条命令导出的是dorm整个数据库,包含建库语句和所有表数据。--default-character-set=utf8mb4是为了防止导出时把中文字符转义成乱码,不加这个参数的话在Windows控制台下导出的SQL文件很可能在重新导入时出现“Incorrect string value”错误。导入时用mysql -u root -p < dorm_backup.sql,前提是先确认目标机器的MySQL版本和字段类型兼容,比如utf8mb4_0900_ai_ci排序规则在MySQL 5.7里是不存在的,直接导入会报“Unknown collation”错误,这种情况要把SQL文件里的排序规则全局替换成utf8mb4_general_ci

5.4 追加验证:用5000条测试数据压出慢查询,再决定要不要加复合索引

当系统基础功能和部署流程全部走通后,最后一件事是验证数据库设计是否真的顶得住评分时的演示压力。我习惯往student和repair表里批量插入几千条测试数据,模拟高年级学生全部入住的情况,然后看几个核心查询的响应时间。

INSERT INTO student (student_no, name, gender, college, major, dorm_room_id, status) SELECT CONCAT('2024', LPAD(n, 4, '0')), CONCAT('测试生', n), IF(n % 2 = 0, '男', '女'), '信息学院', '软件工程', (n % 20) + 1, 1 FROM (SELECT @rownum := @rownum + 1 AS n FROM repair LIMIT 5000) t;

上面这条SQL利用repair表的行数生成5000条学生记录,学号格式是2024000120245000,宿舍号在1到20号宿舍之间循环分配。插入后打开EXPLAIN SELECT * FROM student WHERE name LIKE '测试生1%' AND status = 1;如果type列是ALL,说明当前索引没有被命中,原因是name字段虽然建了索引,但LIKE '测试生1%'的写法是前缀匹配可以命中,可一旦status也加入查询条件,MySQL可能放弃name索引而走全表扫描,这时需要给(name, status)建一个联合索引,并调整SQL里字段的先后顺序与索引一致。

索引加完后,配合Druid连接池监控页/druid/index.html看当前活跃连接数和SQL执行时间,如果maxActive设置过大而MySQL的max_connections默认只有151,需要把maxActive调回20以内,或者在MySQL的配置里调大连接数上限。实训项目的代码里留这些可量化的优化记录,远远比在文档里写“系统性能优越”这种空话更有说服力。

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

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

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

立即咨询