简介一套基于Java、JSP与MySQL的网上订餐系统源码面向Java Web学习者、毕业设计选题者及需要快速搭建订餐演示项目的开发者。工程完整覆盖JSP视图、Servlet控制与MySQL数据三大层体现MVC设计模式含数据库初始化脚本、IDE工程配置与WebContent静态资源可清晰理解从页面提交订餐请求到后端处理并持久化的完整流程。压缩包共1262个文件、47.38MB以css和png静态资源为主另有48个JSP页面、44个Java类、42个Jar依赖包及SQL脚本结构规整便于按模块阅读。已有385人学习下载适合课程设计或Java Web入门实战可直接导入Eclipse或IntelliJ IDEA运行调试结合源码掌握JDBC操作、请求转发与订单状态管理等关键实现。1. 网上订餐系统源码包到手先摸清版本组合再谈跑起来同样是手里一个 zip 包有人两小时把“基于 javajspmysql 简单网上订餐系统源码.zip”跑了起来有人折腾三天还停在登录页报错。区别往往不在代码水平而在有没有按 Java Web 老项目的节奏来先定 JDK 和 Tomcat 版本再看 MySQL 与驱动是否匹配最后才谈改代码。这个项目的业务并不复杂——用户注册登录、菜品列表、加入购物车、提交订单正好覆盖了 JSPServletJDBC 最典型的一条学习链路对做毕设、课设以及刚入行想补 Java Web 功底的开发者来说都值得完整走一遍。本文按我接手这类老项目时的实际操作顺序展开先认工程结构再读关键代码然后搭环境部署最后是跑不起来时最值得查的几个现场。2. 一上来别急着改代码源码目录结构与版本配对是第一步2.1 解压后常见的工程目录src、WebRoot、WEB-INF 各管什么用 IDE 打开之前先在资源管理器里把这个 zip 解开确认目录结构是否完整。这类基于 JSP Servlet 的老项目常见结构是下面这样order-system/ ├── src/ # Java 源码Servlet、DAO、Model │ ├── com/example/dao/ │ ├── com/example/model/ │ ├── com/example.servlet/ │ └── com/example.util/ ├── WebRoot/ # 也常叫 webapp 或 WebContent │ ├── css/ │ ├── js/ │ ├── images/ │ ├── WEB-INF/ │ │ ├── web.xml # Servlet 映射、欢迎页、过滤器配置 │ │ └── lib/ # mysql-connector-java.jar 等依赖 │ ├── login.jsp │ ├── register.jsp │ ├── index.jsp # 菜品列表页 │ ├── cart.jsp │ └── order.jsp └── db.sql # 建库建表脚本有的包会放在 doc 目录下src下面放的是 Java 源码其中 DAO 类负责操作 MySQLServlet 类接收 JSP 页面提交的请求Model 类对应数据库里的用户、菜品、订单等实体。WebRoot是 Web 应用的根目录所有 JSP 页面和静态资源都放在这里容器部署时指向的就是这个目录。WEB-INF是 Web 容器不允许浏览器直接访问的目录web.xml里配置了 Servlet 的 URL 映射lib下放着项目运行所必需的 jar 包——如果缺了 mysql 驱动 jar后面必然会出现ClassNotFoundException。先花五分钟把这几块对上号比直接打开 IDE 看报错要省时间。常见做法是先用tree命令或在资源管理器里大概扫一眼确认WebRoot/WEB-INF/web.xml和src目录都在。如果解压出来只有一堆 JSP 文件而没有 Java 源码那说明 zip 里可能只放了页面部分需要回头找完整包。2.2 版本搭配参考JDK 8 Tomcat 8/9 MySQL 5.7/8.0 为什么稳这类老源码对运行环境极其敏感我一般建议直接采用下面这套组合它覆盖了绝大多数课设和毕设项目的兼容范围组件推荐版本理由JDK1.8老代码基于 Java 8 语法编写切换到 JDK 11 可能出现模块化或依赖兼容问题Tomcat8.5 或 9.x使用javax.servlet命名空间和老源码完全兼容MySQL5.7 或 8.05.7 兼容性最好8.0 需要额外处理时区和 SSL 参数JDBC 驱动mysql-connector-java 5.1.49 或 8.0.x驱动版本必须和 MySQL 版本匹配不能混用JDK 8 到现在仍是 Java Web 老项目的“安全牌”Tomcat 8.5/9 默认支持javax.servlet包源码里import javax.servlet.http.HttpServlet这类语句不需要改动。如果拿到包以后直接用了 Tomcat 10启动时会发现所有和 Servlet 相关的类都找不到这是因为 Tomcat 10 把命名空间换成了jakarta.servlet。这个问题在避坑章节里会专门展开。MySQL 选 5.7 还是 8.0主要取决于本机已经装了什么。我的习惯是如果本机是 MySQL 8.0就不用为了老项目特意重装 5.7只要保证驱动用 8.0.x并且在 JDBC 连接串里把serverTimezone配好即可。反过来如果只有 MySQL 5.7用 8.0.x 的驱动也能连不会有什么问题。最容易翻车的组合是 MySQL 8.0 配 mysql-connector-java 5.1.0 这类老驱动后面连接数据库时会因为时区问题抛异常。3. 拆核心代码用户、菜品、订单三块业务背后的 JSPServletJDBC 链路3.1 建库建表 SQL四张表把用户、菜品、订单与订单明细一次立住网上订餐系统的业务不复杂数据库层面通常只需要四张表用户表、菜品表、订单主表和订单明细表。购物车在简单项目里往往不建表直接用 JSP 的 Session 对象保存。下面这套建表 SQL 是我按这类项目的常见需求整理的可以直接在 Navicat 或 MySQL 命令行执行-- 如果库不存在则创建 CREATE DATABASE IF NOT EXISTS order_system DEFAULT CHARACTER SET utf8mb4; USE order_system; -- 用户表 CREATE TABLE IF NOT EXISTS user ( id INT(11) NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(50) NOT NULL COMMENT 密码课设项目常为明文存储, phone VARCHAR(11) DEFAULT NULL COMMENT 手机号, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 菜品表 CREATE TABLE IF NOT EXISTS food ( id INT(11) NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 菜品名, price DECIMAL(10,2) NOT NULL COMMENT 单价, image VARCHAR(200) DEFAULT NULL COMMENT 图片路径, description VARCHAR(255) DEFAULT NULL COMMENT 描述, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 订单主表 CREATE TABLE IF NOT EXISTS orders ( id INT(11) NOT NULL AUTO_INCREMENT, user_id INT(11) NOT NULL COMMENT 下单用户, total_price DECIMAL(10,2) NOT NULL COMMENT 总金额, status VARCHAR(20) NOT NULL DEFAULT 待确认, create_time DATETIME NOT NULL COMMENT 下单时间, PRIMARY KEY (id), KEY idx_user (user_id), CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES user (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 订单明细表 CREATE TABLE IF NOT EXISTS order_item ( id INT(11) NOT NULL AUTO_INCREMENT, order_id INT(11) NOT NULL, food_id INT(11) NOT NULL, food_name VARCHAR(50) NOT NULL COMMENT 下单时的菜品名快照, price DECIMAL(10,2) NOT NULL COMMENT 下单时单价快照, count INT(11) NOT NULL COMMENT 数量, PRIMARY KEY (id), KEY idx_order (order_id), CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES orders (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 初始化几条菜品数据方便页面展示 INSERT INTO food (name, price, description) VALUES (鱼香肉丝, 18.00, 经典川菜), (宫保鸡丁, 22.00, 微辣下饭), (番茄炒蛋, 12.00, 家常口味);这里有几个细节值得注意。所有表都用InnoDB引擎因为下单时要在订单主表和明细表之间做事务控制MyISAM 不支持事务。字符集统一用utf8mb4比utf8覆盖范围更广能存下 emoji 和一些生僻字也避免菜品名称出现乱码。order_item表里特意冗余了food_name和price两个字段这是为了防止菜品价格或名称日后被修改而导致历史订单对不上账——订单明细必须要存“下单那一刻”的快照而不是下单后再去关联菜品表查询。3.2 JDBC 连接与登录查询换环境后必调的三个参数建完表接下来看 Java 侧怎么连 MySQL。这类项目通常有一个工具类负责创建数据库连接常见名字是DBUtil.java或JdbcUtil.java。核心代码大致如下package com.example.util; 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; // serverTimezone 是 MySQL 8.0 之后必须要加的参数 private static final String URL jdbc:mysql://localhost:3306/order_system ?useUnicodetruecharacterEncodingutf8 serverTimezoneAsia/ShanghaiuseSSLfalse; private static final String USERNAME root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } }这段代码里有三个参数在换环境后必须检查。第一个是DRIVERMySQL 5.7 时代常用com.mysql.jdbc.DriverMySQL 8.0 之后官方驱动改成了com.mysql.cj.jdbc.Driver如果写的是老驱动名Class.forName 会直接报类找不到。第二个是URL里的serverTimezoneAsia/Shanghai——MySQL 8.0 的驱动强制要求指定时区不加就抛The server time zone value Öйú±ê׼ʱ¼ä is unrecognized这是老项目迁移到新 MySQL 最常见的翻车点。第三个是useSSLfalseMySQL 8.0 默认开了 SSL 协商本地开发环境没必要走 SSL不加这个参数有时会报 SSL 连接警告甚至失败。连接拿到手后登录功能的 DAO 层一般长这样用PreparedStatement执行带参数的查询public User findUserByUsernameAndPassword(String username, String password) { String sql SELECT id, username, phone FROM user WHERE username ? AND password ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { User user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); user.setPhone(rs.getString(phone)); return user; } } } catch (SQLException e) { e.printStackTrace(); } return null; }PreparedStatement的好处有两个一是参数用?占位符通过setString传入避免了手工拼接 SQL 字符串带来的注入风险二是同一结构的 SQL 可以被数据库预编译循环执行时性能更好。登录这里有个容易被忽略的点password在简单项目里直接存明文查询时也是明文比对。生产环境绝不能这么写至少要加盐后做 SHA-256 哈希。但课设项目为了演示方便普遍是明文接手后如果要做成作品集建议至少把注册逻辑改成 MD5 存储。3.3 下单要过事务购物车从 Session 落到订单表的核心代码购物车在简单网上订餐系统里一般不单独建表页面把选中的菜品放在 Session 的一个 Map 里MapFood, Integer的 key 是菜品对象value 是数量。用户点击“提交订单”时后端要把这个 Map 拆成一条订单主记录和若干订单明细记录而且必须保证它们同时成功、同时失败——否则就会出现“订单主表有记录明细却是空的”这种脏数据。看下面的下单方法public boolean createOrder(User user, MapFood, Integer cart) { Connection conn null; PreparedStatement ps null; ResultSet keys null; boolean success false; try { conn DBUtil.getConnection(); // 关键点 1关闭自动提交手动控制事务 conn.setAutoCommit(false); // 先算总价 double total 0.0; for (Map.EntryFood, Integer entry : cart.entrySet()) { total entry.getKey().getPrice() * entry.getValue(); } // 插入订单主表并拿到自增主键 String insertOrder INSERT INTO orders(user_id, total_price, status, create_time) VALUES(?, ?, 待确认, NOW()); ps conn.prepareStatement(insertOrder, Statement.RETURN_GENERATED_KEYS); ps.setInt(1, user.getId()); ps.setDouble(2, total); ps.executeUpdate(); keys ps.getGeneratedKeys(); int orderId 0; if (keys.next()) { orderId keys.getInt(1); } // 批量插入订单明细 String insertItem INSERT INTO order_item(order_id, food_id, food_name, price, count) VALUES(?, ?, ?, ?, ?); ps conn.prepareStatement(insertItem); for (Map.EntryFood, Integer entry : cart.entrySet()) { Food food entry.getKey(); ps.setInt(1, orderId); ps.setInt(2, food.getId()); ps.setString(3, food.getName()); ps.setDouble(4, food.getPrice()); ps.setInt(5, entry.getValue()); ps.addBatch(); // 暂存到批处理 } ps.executeBatch(); // 关键点 2一次性提交所有明细 conn.commit(); // 关键点 3全部成功才提交 success true; } catch (Exception e) { try { if (conn ! null) { conn.rollback(); // 任何一个环节失败全部回滚 } } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); } finally { // 实际项目中要依次关闭 ResultSet、PreparedStatement、Connection // 建议用 try-with-resources 自动关闭 } return success; }这段代码把事务控制的三个关键点全占了setAutoCommit(false)告诉 MySQL 先不要自动落盘commit()在所有明细插入成功后统一提交rollback()在出现异常时把所有已执行的 SQL 全部撤销。在关闭自动提交之后如果用普通的executeUpdate()一条条执行明细插入性能会很差这里用addBatch()把多条 SQL 攒在一起最后executeBatch()一次性发给 MySQL减少网络往返。Statement.RETURN_GENERATED_KEYS配合getGeneratedKeys()拿到自增主键是插入主表后获取新订单 ID 的标准做法——不要用“先查 MAX(id)1”这种写法并发时会撞车。4. 从 ZIP 到跑通导入 IDE、改四处配置、部署 Tomcat 的最小步骤4.1 改好这四处配置数据库名、账号、密码、连接 URL把代码导入 IDE 之前先检查项目里连接数据库的配置集中在哪。常见的两种方式一是单独放在src/db.properties文件里二是直接写在DBUtil.java的常量里。无论哪种核心就是下面这四个配置项jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/order_system?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse jdbc.usernameroot jdbc.password123456我一般会把连接串拆分来看避免改错位置。localhost:3306是 MySQL 的地址和端口如果 MySQL 装在了其他机器或 Docker 容器里这里要改成对应 IP 和端口order_system是数据库名和第 3 章建表脚本里的CREATE DATABASE order_system保持一致useUnicodetruecharacterEncodingutf8控制客户端和服务器之间的字符编码漏掉它会导致中文菜名在 JSP 页面上正常显示但一写入数据库就变成问号serverTimezone和useSSL则是 MySQL 8.0 环境下的标配参数。如果项目里只有DBUtil.java而没有 properties 文件直接把常量改掉即可。还有一类老项目会把 jdbc 配置写到WEB-INF/web.xml里的env-entry标签中搜索时重点找jdbc:mysql这个字符串改起来更直观。这里有一个小经验改完配置后先单独写一个带main方法的测试类调DBUtil.getConnection()看能不能拿到连接跑通再部署到 Tomcat能把连接问题和 Web 容器问题隔离开来。4.2 部署到 Tomcat 并验证启动日志和第一个请求该怎么看部署这步不同 IDE 操作路径不一样但核心都一样把项目打成 Web 应用让 Tomcat 指向WebRoot目录。Eclipse 的做法是在 Servers 视图里右键 Tomcat - Add and Remove - 把项目添加进去。IDEA 则是 Run Configuration 里选 Tomcat Server LocalDeployment 标签页添加 Artifact。部署完成后按顺序做三个验证。第一步看 Tomcat 启动日志确认没有 Exception第二步在浏览器访问http://localhost:8080/订单系统名/如果看到登录页或菜品列表页说明应用已经起来第三步打开浏览器 F12 的 Network 面板刷新页面看 HTTP 状态码如果登录接口返回 500说明后端代码或数据库连接有问题需要回控制台看详细堆栈。也可以用命令行快速验证curl -I http://localhost:8080/order_system/login.jspcurl -I只取响应头重点看返回的是 200 还是 404。如果返回 404第一步检查访问的上下文路径和部署时填写的 Application Context 是否一致常见写法是/order_system第二步检查web.xml里是不是配置了welcome-file-list直接把index.jsp设为欢迎页访问根路径可以被自动解析。还要注意 Tomcat 默认端口是 8080如果本机被占用可能已经被人改成 8081启动日志里会有明确提示。4.3 重新编译后的输出目录最容易出现“改了没生效”的地方用 IDE 部署 Tomcat 时项目源码会被编译到 IDE 指定的输出目录。Eclipse 默认是WebRoot/WEB-INF/classesIDEA 则是 target 下的结构。很多人在源码里改了DBUtil.java刷新页面还是老配置就是因为 IDE 增量编译没有把最新的 class 文件同步到 Tomcat 的工作目录。我在本地调试时遇到“改了代码但行为没变”优先做三件事。第一Build 菜单里执行 Rebuild Project强制全量编译而不是增量编译。第二查看 Tomcat 部署路径下WEB-INF/classes里的.class文件修改时间如果时间不是刚刚说明编译产物没过来。第三如果项目里有out或target目录缓存直接删掉重新跑。还有一个常见坑是清理 Tomcat 的 work 目录——Tomcat 会把 JSP 翻译成 Servlet 源码再编译成 class如果 JSP 文件被修改但 work 目录里的缓存没清理访问到的还是旧页面。平时不太需要手动清但遇到 JSP 改动后行为怪异Tomcat/work目录删掉重启一定能解决。5. 常见问题与避坑能编译却跑不起来的 5 个典型现场5.1 驱动类 ClassNotFound不全怪缺 jar更多的是驱动版本和新旧命名现象Tomcat 一启动访问首页就报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者com.mysql.cj.jdbc.Driver。原因分两种。第一种是WEB-INF/lib下根本没有 mysql 驱动 jar 包这种情况在解压源码包后就缺文件去 MySQL 官网下载对应版本的 Connector/J 放进lib目录即可。第二种更隐蔽jar 包在但驱动类名写错了。老驱动对应com.mysql.jdbc.DriverMySQL 8.0 的驱动改名为com.mysql.cj.jdbc.Driver。如果你用的是 mysql-connector-java 8.0.x代码里却还写老名字Class.forName 同样报找不到。解决确认 lib 下 jar 的版本。5.1.x版本用com.mysql.jdbc.Driver8.0.x版本用com.mysql.cj.jdbc.Driver。如果项目里两种类名都有引用统一改成和 jar 匹配的那个。有一个快速验证办法直接解压 jar 包看META-INF/services/java.sql.Driver文件里写的全限定类名那就是当前驱动实际支持的入口。5.2 中文全部变成问号JSP 页面、请求编码、连接串三处都得统一现象菜品名是中文页面显示正常但数据写入数据库后变成???或者 JSP 页面上直接显示乱码。原因字符集在三个环节之间没有对齐。第一JSP 页面顶部缺少% page contentTypetext/html; charsetUTF-8 %第二Servlet 接收请求时没有设置request.setCharacterEncoding(UTF-8)表单提交的中文参数以 ISO-8859-1 解码第三JDBC 连接串缺少characterEncodingutf8。这三个环节有一个不一致中文就可能在某一环变成问号。解决从上到下统一。JSP 页面顶部加 page 指令Servlet 的doPost方法第一行写request.setCharacterEncoding(UTF-8)JDBC 连接串里补useUnicodetruecharacterEncodingutf8。数据库表结构也尽量用utf8mb4并确认连接时 MySQL 的character_set_server是 utf8mb4。改完以后把数据库里已经变成???的旧数据删掉重新插入已经损坏的字符不会自动恢复。5.3 老源码碰到 Tomcat 10javax.servlet 变成 jakarta.servlet 之后的翻车现象源码包在别人的 JDK 8 Tomcat 8 上跑得好好的自己用的是 Tomcat 10/11一启动就报ClassNotFoundException: javax.servlet.http.HttpServlet或者 IDE 里大量编译错误。原因Tomcat 10 开始被移交到 Jakarta EE 体系Servlet API 的包名全部从javax.servlet改为jakarta.servlet。老项目源码里所有import javax.servlet.*都找不到对应的 jar因为 Tomcat 10 自带的 Servlet API 只有jakarta.servlet命名空间。解决最省事的做法是把 Tomcat 换成 8.5 或 9.x不要改代码。如果必须用 Tomcat 10就需要全局替换 Java 文件和 JSP 里的 import 和 page 指令比如importjavax.servlet.http.HttpSession改成importjakarta.servlet.http.HttpSession。但要注意项目 lib 下的 servlet-api.jar 如果还是老的也要一并换成新版本。对于一套练手项目换回 Tomcat 9 的成本远低于改所有源码我个人强烈建议直接用 Tomcat 9。5.4 MySQL 连接串里的时区与 SSL8.0 换了驱动就连不上的真原因现象JDBC 连接报错提示The server time zone value Öйú±ê׼ʱ¼ä is unrecognized或者Communications link failure。原因MySQL 8.0 的连接驱动强制要求客户端指定时区而 MySQL 服务端默认时区在某些系统上返回的是系统本地描述驱动解析不了。另外 MySQL 8.0 默认启用 SSL 握手本地开发环境没有配置证书时连接过程会多一层协商某些驱动版本会直接失败。解决在 JDBC URL 末尾拼上serverTimezoneAsia/ShanghaiuseSSLfalse。如果用了是 mysql-connector-java 5.1.x 的老驱动建议直接升级到 8.0.x老驱动和 MySQL 8.0 服务端的兼容性并不好。还有一类情况是改完参数仍然Communications link failure这时先去telnet 127.0.0.1 3306确认 MySQL 端口可通再检查 MySQL 的bind-address配置是否只允许本机连接。5.5 提交表单就 404web.xml 的映射和页面 action 必须对得上现象点击“登录”或“提交订单”浏览器地址栏变成对应 Servlet 的映射地址但页面返回 404Tomcat 控制台没有任何输出。原因JSP 表单的action写的路径和web.xml里servlet-mapping的url-pattern不一致。比如表单写成actionLoginServlet而 web.xml 里映射的是/login请求到达 Tomcat 后找不到对应 Servlet只能 404。解决优先用“相对项目根路径”的方式在 JSP 里统一写成${pageContext.request.contextPath}/login这样不管部署时的上下文路径叫什么都能保证请求发到正确的 Servlet 上。另一个排查点是 Servlet 类上如果用了WebServlet注解同时又保留了 web.xml 里的 XML 配置IDEA 会优先按注解处理两种映射并存时行为非常迷惑人。这种项目我从头到尾只用一种方式管理映射要么全部注解要么全部 web.xml不要混用。6. 进阶一步用 Druid 替换裸 JDBC再查订单数据是否真落库项目跑通以后如果想把这段经历写进简历或者作为 Java Web 学习成果展示有一个很小但很加分的改造把DBUtil里的DriverManager.getConnection换成 Druid 连接池。裸 JDBC 每次请求都要经历“建立连接 - 执行 - 断开连接”的完整过程而连接池维护一批复用连接下单场景下的响应时间和数据库压力都有明显改善。package com.example.util; import com.alibaba.druid.pool.DruidDataSource; import java.sql.Connection; import java.sql.SQLException; public class DBUtil { private static DruidDataSource dataSource; static { dataSource new DruidDataSource(); dataSource.setDriverClassName(com.mysql.cj.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/order_system ?useUnicodetruecharacterEncodingutf8 serverTimezoneAsia/ShanghaiuseSSLfalse); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(3); // 启动时创建 3 个连接 dataSource.setMaxActive(10); // 最大连接数 dataSource.setMaxWait(3000); // 获取连接超时时间单位毫秒 } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }替换的连接池后业务代码几乎不用动因为getConnection返回的还是java.sql.Connection接口DAO 层原样使用。initialSize3可以让 Tomcat 启动时就预建连接而不是等第一个用户请求来才连接数据库避免高峰期首单请求卡顿maxWait3000是一个自我保护当连接被占满时新请求等待 3 秒就放弃不让客户端一直挂起。代码改完后真正要给自己的改造一个交代验证订单数据是否完整落库。打开 MySQL 命令行执行下面这条 SQL把订单主表、用户表、订单明细表关联起来查一次SELECT o.id AS order_id, u.username AS 下单用户, o.total_price AS 总金额, o.status AS 状态, COUNT(oi.id) AS 菜品项数, SUM(oi.count) AS 菜品总份数 FROM orders o JOIN user u ON o.user_id u.id LEFT JOIN order_item oi ON oi.order_id o.id WHERE o.id 1 GROUP BY o.id;如果菜品项数和你在页面上加购的数量一致说明下单事务没有丢明细。我个人习惯每接手一个老项目都先做一次这样的数据核对再去读界面逻辑。把 Druid 换上去这步顺便帮我养成了看连接池参数的习惯后来项目里凡是涉及数据库的地方我都会先确认连接串字符集和时区是否配齐——这两个参数就是老项目里最常见的隐形坑。希望这篇笔记能帮你少走几步弯路让这个简单网上订餐系统真正跑起来。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?