☰
JSP+SQLServer网上花店系统毕设指南:库表设计、部署与避坑
2026/9/26 15:02:57 网站建设 项目流程

简介:一份以JSP和SQLServer为核心、完整覆盖网上花店系统从需求分析到实现部署的毕业设计资料包,适合正在做电商类Web项目的学生或需要参考JSP+Servlet+JDBC开发流程的入门开发者。包体共1140个文件,约8.67MB,其中79个jsp页面与22个java类负责前端展示与后端业务逻辑,18个css与6个js控制页面样式和交互,8个db文件及mdf、ldf为SQLServer数据库文件,另含550个gif和391个jpg图片素材、sql脚本、class编译产物及doc论文文档,便于直接导入运行和对照学习。目前已有190人学习下载。资料价值在于不仅提供可直接部署的网上花店系统源码,还包含12011字论文,详细阐述了用户注册登录、商品浏览、购物车管理、订单处理、支付接口集成等核心功能的设计思路,以及ER图数据库建模和JDBC连接SQLServer执行CRUD操作的具体实现,是理解JSP动态网页技术与关系型数据库协同开发的优质实战案例。

1. 网上花店系统不是过时选题:JSP + SQLServer 组合为什么值得认真对待

毕业设计里有一个高频选择,就是 JSP 网上花店系统——技术栈老,但业务闭环完整,从商品浏览、加入购物车、订单提交到后台管理,正好覆盖软件工程课程的核心知识点;配上 SQLServer 数据库和一篇 12000 字级别的论文,就是一套标准的三层结构毕设。真正上手的人会很快发现,难的不是写 JSP 页面,而是让程序、数据库、论文三者在答辩前保持同一条逻辑线。这篇笔记把整套系统的库表设计、JDBC 连接、部署打包和常见报错拆开讲,适合拿到类似代码包后先验证再改写的应届生,也适合想快速把 JSP 项目跑起来做二次开发的初学者。

2. 选型与架构:为什么 JSP + SQLServer 的组合还能打

2.1 JSP 不是过气技术:毕设场景里它反而是默认项

JSP 全称 Java Server Pages,本质是在 HTML 里嵌入 Java 片段,由 Servlet 容器在服务端编译成 Servlet 再输出响应。放到今天的互联网一线,这类写法确实不是主流,前后端分离和模板渲染占了上风。但留意一个细节:高校的课程设计和毕业设计,大部分仍然以 JSP 作为默认教学载体。原因不是技术保守,而是这套体系的可见性最好——写一个 .jsp 文件,浏览器能看到效果,打断点能进去,改环境能复现,对一个需要短期交付论文和可运行系统的学生来说,这正是性价比最高的组合。

如果换成 Spring Boot + Vue 那套,学习曲线会压在环境搭建和构建工具上,页面、接口、数据库三者之间的映射关系藏在注解背后,写论文时很难把“我做了什么”讲清楚。JSP 花店系统则相反,一个请求从 JSP 页面发起,经过 Servlet,进入 DAO,最后落到 SQLServer,每一层都是独立文件,答辩画流程图时几乎不需要编造。项目里常见的“jsp个人信息展示页面”和“jsp入门”这类需求,靠这套结构也能直接对应上,不需要额外引入框架概念。

所以选这个方向的人,不用被“JSP 过气”的说法劝退。它适合人数少、周期短、要快速出成果的场景,唯一要接受的是:你必须把 Java 基础语法和 JDBC 搞熟,因为框架不会替你遮住这些问题。换个角度想,这也是好事——面试被问到 Servlet 生命周期、Session 原理时,你比背八股文的人多了一整个能跑的项目。

2.2 三层结构怎么拆:JSP、Servlet、DAO 各管一段

拿到这套源码时,第一步不是急着启动,而是先看目录结构。常见做法是把代码分成三层:JSP 页面放在 WebRoot 或 webapp 下,负责展示;Servlet 放在 controller 包,负责接收请求和跳转;DAO 放在 dao 包,里面全是 JDBC 操作 SQLServer 的代码。一个典型请求的流转是:用户点击商品分类,浏览器向 Servlet 发请求,Servlet 调 DAO 查数据库,把结果放进 request 作用域,再 forward 到 JSP 页面渲染。

下面这段代码展示的是商品列表查询在 Servlet 里的典型写法:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String type = req.getParameter("type"); if ("list".equals(type)) { FlowerDAO dao = new FlowerDAO(); int cid = Integer.parseInt(req.getParameter("cid")); List<Flower> list = dao.findByCategory(cid); req.setAttribute("flowerList", list); req.getRequestDispatcher("/flower_list.jsp").forward(req, resp); } else if ("detail".equals(type)) { // 按 id 查单件商品,转发到详情页 int id = Integer.parseInt(req.getParameter("id")); Flower flower = new FlowerDAO().findById(id); req.setAttribute("flower", flower); req.getRequestDispatcher("/flower_detail.jsp").forward(req, resp); } }

这段代码要表达的不仅是写法,还有两个关键选择。第一,用 forward 而不是 redirect,是因为 forward 是服务端内部跳转,request 里塞进去的 flowerList 还能在 JSP 里通过 EL 表达式取出来;redirect 会发起第二次请求,原来 request 里的数据全部丢失,除非改存 session。第二,参数 cid 和 id 从 request.getParameter 拿回来是字符串,必须转 int,这里没做异常处理,真实项目中用户乱传参数会导致 500,答辩时被问到可以顺势说“这里应该加 try-catch 并回传错误提示”。

Service 层在这类毕设项目里经常被省略,DAO 直接暴露给 Servlet。如果你想让项目结构更完整,可以在 Servlet 和 DAO 之间加一层 Service,把“查购物车、算总价、生成订单”这类需要组合多个 DAO 操作的业务放进去,论文里也能多画一张层次图。

2.3 SQLServer 的位置:实例名、端口和 JDBC 连接串

SQLServer 不像 MySQL 那样默认一装就能连,它最大的“玄学”来源是实例名和协议开关。本机安装时如果只选择了默认实例,连接串里可以用 localhost 或 127.0.0.1;如果装的是命名实例,比如 SQLEXPRESS,连接串就要写成 localhost\SQLEXPRESS 这种格式。另一个常年踩坑点是 TCP/IP 协议默认可能被禁用,JDBC 是走 TCP 连接的,协议没开,代码写得再对也是“无法连接”。

数据库连接信息通常集中在一个文件里,常见的是 src 下的 db.properties,或者直接写在 DBUtil.java 的静态块中。用 properties 文件的好处是改配置不用重新编译,但毕设项目图省事,很多源码是直接写在 Java 里的。两种都在拿到代码后先找这两个位置。下面是 properties 文件的标准内容:

driver=com.microsoft.sqlserver.jdbc.SQLServerDriver url=jdbc:sqlserver://localhost:1433;DatabaseName=flower username=sa password=你的密码

这里几个参数要解释清楚。driver 是微软 JDBC 驱动的类名,不是 MySQL 的 com.mysql.jdbc.Driver,两者不能混用。url 里的 1433 是 SQLServer 默认端口,DatabaseName 后面跟的是库名,注意这里不需要显式写 characterEncoding,SQLServer 驱动的编码行为由数据库排序规则决定,和 MySQL 的 URL 参数体系不一样。username 和 password 对应 SQLServer 登录名,很多教学环境直接用 sa,但如果你装的是 SQLServer 2019 之后的版本,默认可能启用了仅 Windows 身份验证,sa 登录会报错,需要在 SSMS 里把服务器属性改成“SQL Server 和 Windows 身份验证模式”并给 sa 设密码。

为什么在 MySQL 满地走的情况下还选 SQLServer?对毕设来说理由很实在:高校机房和旧笔记本上常见的是 Windows + SQLServer 组合,安装包离线可用,备份文件 .bak 还原方便,图形化工具 SSMS 对不熟悉命令行的学生友好。如果你手头的源码提供的是 .bak 文件,大概率也是按这个环境准备的。

3. 把花店业务装进 SQLServer:库表设计与核心 SQL

3.1 一个花店系统需要哪些表:从业务闭环反推

网上花店系统的业务场景和电商后台是同一个模子:用户注册登录、浏览花卉分类、把花加入购物车、提交订单、管理员在后台维护商品和处理订单。按这个流程反推,最少需要 7 张表。这个表清单也是后面核对论文 E-R 图的基准,很多论文与代码对不上,问题都出在表数量和字段不一致上。

表名作用关键字段
admin后台管理员登录id, username, password
member前台会员信息id, username, password, phone, address
category花卉分类id, name
flower花卉商品id, name, category_id, price, stock, pic, description
cart购物车id, user_id, flower_id, quantity
orders订单主表id, user_id, total, status, address, create_time
order_item订单明细表id, order_id, flower_id, price, quantity

花店系统的“花”本身没有尺码、颜色这些 SKU 属性,所以商品表比服装电商简单,不需要拆 SKU 表。但要注意订单明细表里的 price 字段,它存的不是 flower 表里的实时价格,而是下单那一刻的单价快照。这个设计答辩时几乎必问,答得出来就是加分项,答“我直接查 flower 表”就会被追问“那花涨价之后,历史订单金额怎么算”。字段的类型选择也会影响后续代码:比如 status 字段在 orders 表里用 tinyint 或 int 都行,0 表示待付款、1 表示已付款、2 表示配货中、3 表示已完成,比直接存中文更规范,程序里用 switch 映射成页面文字。

如果你的代码包里还有一张 stock_log 库存流水表,那说明作者做了库存审计,属于加分设计;没有也没关系,在事务里保证库存扣减与订单生成一致即可,下文第 3.3 节会说到。

3.2 建表脚本的关键点:identity、nvarchar 和 numeric

拿到 .sql 脚本后不要直接无脑执行,先看它的建表语句写得好不好。好的建表脚本要符合三个习惯:主键用自增列、中文用 nvarchar、价格用 numeric 而不用 float。下面是 flower 表的典型建法:

create table flower ( id int identity(1,1) primary key, name nvarchar(50) not null, category_id int not null, price numeric(10,2) not null, stock int not null default 0, pic nvarchar(100) null, description nvarchar(500) null );

identity(1,1) 是 SQLServer 的自增列,从 1 开始每次加 1,等价于 MySQL 的 auto_increment,但写法完全不同——如果你把 MySQL 的习惯带过来,会在 SQLServer 上报错。name 和 description 用 nvarchar 而不是 varchar,是因为 nvarchar 按 Unicode 存储,中文、日文都不会出现乱码或长度截断问题。price 用 numeric(10,2) 表示最多 10 位数字、小数点后保留 2 位,money 类型也可以但精度控制不如 numeric 直观;用 float 存价格在计算总价时会出现 0.1 + 0.2 = 0.30000000000000004 这种“翻车”现场,答辩时被看到很尴尬。stock 字段加 default 0 是防止插入数据时漏掉库存字段导致空值。

外键在这个表里体现在 category_id 上,但很多毕设源码为了省事不建物理外键,只用逻辑关联。我的建议是:脚本里可以不加物理外键,但表关系必须清晰,因为论文的 E-R 图是按逻辑关系画的,物理外键反而会在插入测试数据时带来顺序上的麻烦。orders 和 order_item 之间同理,主表订单 id 通过程序逻辑传给明细表,而不是靠数据库约束强绑。

3.3 三条核心 SQL:商品列表、加购、下订单事务

花店系统里有三块 SQL 是论文和答辩的高频区:商品查询、购物车加购、下单事务。先看商品列表,最常见的是按分类筛选,同时支持关键字模糊搜索:

select id, name, price, pic, stock from flower where category_id = ? and status = 1 and name like '%' + ? + '%' order by id desc;

这里的 status 字段如果原表没有,可以忽略。注意 SQLServer 的字符串拼接用 + 而不是 MySQL 的 CONCAT,? 是 JDBC 预处理语句的占位符。like 里的 % 和关键字用 + 拼起来是为了实现“包含”匹配,如果你直接把 ? 填成 %玫瑰% 也可以,但那样参数含义就不纯粹了。

加购的 SQL 是另一个细节密集点。用户点击“加入购物车”,如果同一件商品已经在车里,应该把数量加 1,而不是再插一条重复记录。常见的写法是先用 exists 判断,再决定 update 还是 insert:

if exists (select 1 from cart where user_id = ? and flower_id = ?) update cart set quantity = quantity + 1 where user_id = ? and flower_id = ?; else insert into cart(user_id, flower_id, quantity) values(?, ?, 1);

这段逻辑单独看没问题,但要注意 if exists 和后面的 update 之间存在并发窗口,两个用户同时点击时可能都走了 exists 分支导致数量不对。毕设阶段用这种先查再写的写法完全可以,但如果想展示更严谨的功底,可以把判断和更新合并成一条 update,再判断影响行数,影响 0 行才走 insert。面试官看到这个细节,会认为你考虑过并发问题。

下单是整个系统最需要事务的地方。用户提交订单时要做四件事:往 orders 表插一条主订单;从 cart 和 flower 关联查出商品快照插入 order_item;扣减 flower 表的库存;清空该用户的购物车。这四步任何一步失败,都不能留下半截数据:

begin tran; declare @userId int = 1; declare @orderId int; insert into orders(user_id, total, status, create_time) values(@userId, 0, 0, getdate()); set @orderId = scope_identity(); insert into order_item(order_id, flower_id, price, quantity) select @orderId, f.id, f.price, c.quantity from cart c inner join flower f on c.flower_id = f.id where c.user_id = @userId; update f set f.stock = f.stock - t.qty from flower f inner join ( select flower_id, sum(quantity) as qty from cart where user_id = @userId group by flower_id ) t on f.id = t.flower_id; delete from cart where user_id = @userId; -- 检查库存是否被扣成负数,是则回滚 if exists ( select 1 from flower where stock < 0 ) rollback; else commit tran;

这里要解释两个知识点。第一,scope_identity() 取的是当前会话、当前作用域内最后生成的自增值,比 @@identity 更安全,因为 @@identity 可能会被表的触发器改成别的值。第二,订单初始化时 total 写成 0,真实项目应该先算出总价再插入,或者插入后用明细表反算更新,展示的这段是流程骨架。事务用 begin tran 开启,commit 提交,rollback 回滚,配合最后的库存负值检查,基本覆盖了“防超卖”的最低要求。

4. 从源码到能跑:JSP 网上花店系统的部署清单与配置解读

4.1 环境搭配:JDK、Tomcat、SQLServer 和 IDE

很多人在拿到源码后卡在环境搭配上,其实这套项目最稳妥的组合非常固定:JDK 8、Tomcat 8.5 或 9、SQLServer 2008R2 到 2019 都可以,IDE 用 IDEA 社区版或 Eclipse 都行。JDK 8 是最保守的选择,因为项目里的旧依赖和编译参数在 JDK 11 上不一定兼容;Tomcat 8.5 支持 JSP 2.3 和 Servlet 3.1,对毕设项目完全够用。如果你装的是 Tomcat 10,要特别小心——它默认走 Jakarta EE 命名空间,很多老项目的 import javax.servlet 会直接编译不过。

这里顺便说一个经常被问到的点:nginx 支持 jsp 吗?答案是 nginx 本身不解析 JSP,它只能转发静态请求和反向代理。JSP 页面必须先交给 Tomcat 编译执行,再由 Tomcat 把生成的 HTML 返回给浏览器。你可以在 nginx 里配置 location / 转发到 http://localhost:8080,但网上花店系统这类毕设项目直接访问 Tomcat 端口就够了,没有必要前置 nginx。

确认环境是否就绪,先打开命令行敲两个命令:java -version 看 JDK 版本;然后在 Tomcat 的 bin 目录下执行 catalina.bat version(Windows)或 catalina.sh version(Linux),看 Tomcat 能否正常输出版本号。Tomcat 启动依赖 JAVA_HOME 环境变量,如果启动一闪而过,去环境变量里确认 JAVA_HOME 指向的是 JDK 安装目录,而不是 jre 目录。

4.2 还原数据库和改连接串:拿到 .bak 或 .sql 之后的第一步

这套源码配的是 SQLServer 数据库,交付形式常见有两种:.bak 备份文件或 .sql 脚本文件。.bak 文件在 SSMS 里右键“还原数据库”即可,注意目标库名要与你代码里的 DatabaseName 一致,通常是 flower。.sql 文件则直接在 SSMS 里打开执行,但执行前先确认脚本开头有没有 create database 语句,如果没有,要手动先建一个空库再执行。

用命令行还原 .bak 的效率更高,也方便写成文档复现步骤:

sqlcmd -S localhost -U sa -P "你的密码" -Q "restore database flower from disk='D:\flower.bak' with replace"

这条命令的参数含义是:-S 指定服务器实例,-U 是登录名,-P 是密码,-Q 后面跟要执行的 SQL 语句。restore database 从磁盘文件还原,with replace 表示如果 flower 库已存在就覆盖。注意 with replace 是不可逆操作,执行前确认这个库不是你正在用的库,否则就是没有后悔药可吃的误操作。还原完成后,用 SSMS 刷新看看 flower 库下是否出现了前面说的 7 张表。

还原只是第一步,真正的坑在连接串。打开源码里的 db.properties 或 DBUtil.java,把 url、username、password 改成你自己环境的实际值。我之前处理过一份源码,连接串写的是 jdbc:sqlserver://192.168.1.100:1433;DatabaseName=flower,那是作者实验室的内网 IP,直接跑必然超时。改成 localhost 或 127.0.0.1 即可解决。改完连接串不是刷新页面就行,Java 代码改了必须重新编译再重新部署,很多初学者栽在这步。

4.3 war 包部署还是 IDE 直接跑:两种方式怎么选

代码跑起来有两种方式。调试阶段推荐在 IDEA 里配置 Tomcat Server 直接启动,改代码热部署方便;演示和交付阶段建议打包成 war 放进 Tomcat 的 webapps 目录,这是“传统jsp项目打包war”的标准做法。war 包本质上是一个规定目录结构的 zip,里面包含编译后的 class、JSP 页面、依赖 jar 包和 web.xml。IDEA 里通过 Build Artifacts 生成 war 包,或者在 pom.xml 里配置 maven-war-plugin 后执行 mvn package。

把生成的 war 包复制到 Tomcat 的 webapps 目录下,启动 Tomcat 后会自动解压,访问路径由 war 包文件名决定。比如你放进去的是 flower.war,访问地址就是 http://localhost:8080/flower/;如果你放的是网上花店系统.war,地址会有一段 URL 编码,非常难看。我一般会先把 war 包重命名为简短英文名再部署。如果 Tomcat 在启动时报端口 8080 被占用,去 conf/server.xml 里改 HTTP 端口,或者在任务管理器里结束占用进程。

部署完先看日志再访问页面。Tomcat 的日志在 logs 目录下,catalina.日期.log 记录启动过程,localhost.日期.log 记录应用抛出的异常。日志里看到 Exception 不要慌,大部分问题集中在数据库连接和 jar 包缺失两类,顺着堆栈往上找就能定位。页面如果 404,先看 webapps 下解压出来的目录结构对不对,JSP 页面是否在根目录或对应子目录下,以及 web.xml 里配置的欢迎页文件名是否真实存在。

5. 部署与答辩前避坑:JSP + SQLServer 的排查顺序

5.1 数据库连不上:先分清是哪一层的问题

现象:启动 Tomcat 后访问页面,出现 “The TCP/IP connection to the host failed” 或 “Connection refused” 的异常堆栈。

原因:数据库连不上有 80% 是环境问题而不是代码问题。最常见的是 SQLServer 的 TCP/IP 协议没有开启,其次是连接串里的实例名或端口写错,还有一小部分是驱动 jar 包版本与 JDK 不匹配。SQLServer 的配置管理器是排查的第一站。

解决:打开 SQLServer 配置管理器,找到“SQL Server 网络配置”,确认 TCP/IP 协议已启用,然后在 IP 地址页签里确认端口为 1433,改完必须重启 SQLServer 服务。再用命令行验证:sqlcmd -S localhost,1433 -U sa -P “密码”,能连上说明服务和端口没问题。排除完之后再检查代码里的连接串,按第 4.2 节的方式逐项核对。按这个顺序排查,比盯着 IDEA 控制台瞎猜快得多。

5.2 字符串转数字报错与 string_split 不存在:老库遇见新函数

现象:页面报 “Conversion failed when converting the nvarchar value ‘xxx’ to data type int” 或 “Invalid object name ‘string_split’”。

原因:第一条是隐式转换失败,SQLServer 在把 nvarchar 字段与 int 比较时,如果字段里存了空字符串、中文或多余空格,就会直接报错。第二条是函数版本问题,string_split 是 SQLServer 2016 才引入的函数,你连的库如果是 2008R2 或 2012,代码里用了这个函数必然报对象名无效。

解决:字符串转数字前先用 TRY_CONVERT 或 ISNUMERIC 判断,TRY_CONVERT 在转换失败时返回 null 而不是报错,是更安全的写法。写法示例:select case when ISNUMERIC(price) = 1 then CONVERT(int, price) else 0 end from flower。注意 ISNUMERIC 对正负号、小数都返回 1,所以精确定位还是 TRY_CONVERT 更稳。至于 string_split,要么把数据库升级到 2016 以上,要么改成自定义分隔函数,不要在兼容级别 100 的库上硬跑。

5.3 中文乱码:页面、请求、数据库三处统一

现象:一种是把商品花名插进数据库后页面显示问号;另一种是 JSP 页面显示正常,但从页面提交中文到数据库后变成乱码。

原因:这属于编码链条不一致。JSP 文件本身的 pageEncoding 不是 UTF-8,Servlet 里没设置 request 和 response 的编码,数据库表中的列用了 varchar 而排序规则又不是中文前缀,这三点任何一处出问题都会乱码。SQLServer 这边对 JDBC 驱动的编码处理与 MySQL 不同,它在连接串层面不太强调 characterEncoding 参数,而是靠数据库排序规则和列类型决定存储方式。

解决:统一三处:JSP 页面头写 pageEncoding="UTF-8",Servlet 在 doGet/doPost 开头设置 request.setCharacterEncoding("UTF-8"),数据库表和列统一用 nvarchar。如果你已经插了乱码数据,先清理数据再调整排序规则,最后才改代码重试。排查时先分清是存入前乱还是取出后乱——在登录注册处打断点看 request 里的值,如果这里已经完全乱码,问题在页面和请求编码;如果这里正常而数据库里乱,那问题在数据库列类型。

5.4 登录态失效和后台页面被直接访问

现象:用户在商品页点“我的购物车”,被弹回登录页,刷新一下又掉线;更严重的是不登录直接访问 /admin/ 下的页面也能打开。

原因:第一种情况是 session 超时设置太短,或者项目在跳转过程中把 session 弄丢了;第二种情况是后台压根没有登录校验过滤器,只要知道 admin 页面的路径就能绕过登录。毕设答辩时,老师大概率会当场试一下直接输入后台地址,这一关过不去很扣分。

解决:用 Filter 解决权限问题,写一个 LoginFilter 拦截 /admin/* 路径,从 session 里取管理员对象,取不到就重定向到登录页。session 超时在 web.xml 里配置:

<session-config> <session-timeout>30</session-timeout> </session-config>

单位是分钟,30 分钟足够演示。另外登录成功后建议调用 request.getSession().invalidate() 再重新创建 session,防止会话固定攻击,这个点答辩时主动讲出来,比被动回答要好。

5.5 论文与代码对不上:答辩前怎么快速自查

现象:答辩老师翻论文里的功能模块图,指着一个模块问“这个功能代码在哪”,结果代码里根本没有;或者论文里的 E-R 图有 8 张表,代码里只有 5 张。

原因:论文在代码写完之后才开始排版,作者在论文里“优化”了设计,但代码没有同步改。毕业生时间紧张,代码和论文是两条线在推进,最后没合并。

解决:以数据库表清单作为基准来对齐。先打开论文里的 E-R 图或数据表说明,数一下有几张表;再打开数据库脚本,数一下实际建了几张表。表数不一致,改论文的描述比改代码快。其次,每个功能模块图对应一个 DAO 类的方法,比如论文写了“商品分类浏览功能”,代码里就应有 FlowerDAO.findByCategory。自查时画一张表:功能模块、对应 JSP、对应 Servlet、对应 DAO 方法、对应数据库表,五列填齐,论文和代码的对应关系就一目了然了。

6. 让系统从“能交差”变“能讲”:先改事务与预编译两个点

6.1 先改两个点:PreparedStatement 与下单事务

拿到能跑的源码后,不要急着去美化页面,先把两个技术点改掉,这是答辩时最容易被追问、也最能体现你真实理解的地方。第一个点是 DAO 层里如果有字符串拼接 SQL 的写法,全部改成 PreparedStatement。拼接写法是 String sql = “select * from flower where id = ” + id,改成 PreparedStatement 后用 ? 占位,setInt 绑定参数,SQL 注入就堵住了。这个改动量不大但效果明显,老师问“你怎么防 SQL 注入”时,你可以直接指代码回答。

第二个点是下单方法必须包在事务里,对应第 3.3 节的四步操作。如果你拿到的源码里下单是分开多条 update 执行的,中间任何一步失败就会留下“订单没生成但库存扣了”或“购物车清空但订单没建”的脏数据。把整个方法放到同一个 Connection 上执行,用 setAutoCommit(false) 关闭自动提交,最后 commit,异常里 rollback。这两处改完,整个系统的业务可信度会上一个台阶。

6.2 演示前必查的三个验证点

答辩演示时,老师不会关心你页面好不好看,只会验证业务逻辑是否严谨。有三个验证点值得在演示前反复走一遍。第一,同一件花加两次购物车,数据库里是一行数量 2,而不是两行重复记录;第二,提交订单后,flower 表的库存减少,order_item 表里出现对应的商品快照,且订单金额与商品单价乘数量一致;第三,把库存改成 1,再提交两件花的订单,系统数据不乱,要么提示库存不足,要么事务回滚。

我自己处理这类 JSP + SQLServer 项目时养成了一个习惯:先还原数据库,再改连接串,最后才碰代码——这样每次出问题都能快速区分是代码问题还是环境问题。这套顺序也帮我躲过了不少“玄学”报错。希望这篇笔记能让你拿到源码后少走弯路,把时间花在真正能加分的地方。

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

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

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

立即咨询