新闻详情

新闻详情

首页 / 资讯中心 / 详情

JavaWeb图书管理系统课设:JSP+Servlet+MySQL三层架构实战

发布时间:2026/9/28 15:07:55来源:尧图网络
JavaWeb图书管理系统课设:JSP+Servlet+MySQL三层架构实战
简介面向JavaWeb课程设计场景的图书管理系统完整项目包适合正在完成课设或希望系统掌握JavaWeb开发流程的学生。项目基于MVC分层整合MyBatis、JSP、Servlet、jQuery、ECharts和Bootstrap覆盖后端数据访问、前端页面交互与可视化统计等环节可作为课程设计报告和代码讲解的可靠参考。压缩包共179个文件约4.44MB包括14个Java源文件、28个JSP页面、32个XML配置/映射文件、20个JS脚本以及SQL脚本、CSS样式、数据库相关配置和部分编译产物结构上能看出从建库脚本到页面展示的完整链路。该资源已有2158人学习适合用来对照完整项目结构理解MyBatis映射与Servlet控制器写法也能参考ECharts统计图表、Bootstrap响应式界面和jQuery交互的实现方式对完成图书管理类课设或熟悉JavaWeb常用技术组合都有直接帮助。1. JavaWeb 图书管理系统为什么它是课设里的常青树图书管理系统大概是 JavaWeb 课程设计里最老、最多人做也最容易做得“好像会了但一问就跪”的题目。湖科大的这门课设要求通常是 JSP Servlet MySQL 三层架构做用户登录、图书 CRUD、借还书这几大块。表面看功能不多但真要拿高分需要把事务、分页、模糊查询、会话管理全部串起来。这篇笔记我按自己做过的方案从 IDEA 配置到数据库建表再到核心代码逐行落地把你提交代码后可能被答辩老师追问的细节一并讲透。这套方案适合两类人一类是 JavaWeb 刚学完、想找一个能真正跑通而不是只改改界面的课设另一类是已经用 SSM 或 Spring Boot 写过项目回头补 JavaWeb 原生栈练功的。下面所有代码我都按 JDK 1.8 Tomcat 9 MySQL 8.0 验证过环境不匹配的情况单独放在第 5 章。2. 环境与工程骨架把 IDEA、Tomcat、MySQL 串起来2.1 版本选型为什么是 JDK 1.8 Tomcat 9 而不是 JDK 17 Tomcat 10很多同学第一次建 Web 项目时IDEA 里默认是 JDK 17Tomcat 下载了最新的 10.x然后代码一跑就发现import javax.servlet.*全部报红。原因很直接Tomcat 10 开始把javax.servlet迁移成了jakarta.servlet老教材里的代码全部报废。要做课程设计最省事的组合是 Windows JDK 1.8 IDEAUltimate 或 Community 都行 Tomcat 9.0 MySQL 8.0。这个组合里javax.servlet还在教材和网上大部分代码能直接复用。MySQL 用 8.0 是因为 5.7 的驱动连接串写法不一样且 8.0 默认字符集对中文更友好。如果你电脑上已经装了 JDK 17不用卸载在 IDEA 的 Project Structure 里单独给这个项目设置 1.8 SDK 即可Tomcat 运行时也会用这个 SDK。2.2 新建工程与导入依赖的三种方式创建项目的路径建议选File → New → Project → Java Enterprise左侧选 Web Application。这一步会自动生成src目录和web/WEB-INF骨架比手动建 Maven 工程少踩很多坑。不用 Maven 的原因是课程设计往往要求“提交整个工程即可”Maven 在无网或内网环境下反而会卡在依赖下载。依赖就一个mysql-connector-java。三种放 jar 的方式按可靠性排序下载 mysql-connector-java 8.0.x 的 jar 包直接复制到web/WEB-INF/lib目录下这个目录里的 jar 会被 Tomcat 自动加载最稳IDEA 里 File → Project Structure → Modules → Dependencies → 加号 → JARs这种方式只在开发期有效运行时常有 ClassNotFoundMaven 方式适合后面想往 Spring Boot 方向走的同学。我推荐第一种原因是项目拷贝到别的电脑也能跑不依赖 IDEA 的配置。需要注意的是不要同时用方式 1 和方式 2否则 jar 包会出现两份Tomcat 加载时可能会因为类冲突报一些极难排查的错。2.3 Tomcat 配置的完整步骤在 IDEA 里点击右上角Add Configuration → 加号 → Tomcat Server → Local。这里有个细节很多教程让你先配置Application server指向 Tomcat 安装目录的 bin 上一级这一步可以省因为 IDEA 会在启动时自动找。关键是下面的Deployment 页签点加号选 Artifact正常会出现项目名:war exploded选它而不是 warApplication context 填/这样启动后访问地址就是http://localhost:8080/不用再带工程名前缀Server 页签里的 On frame deactivation 选项选 Update classes and resources改 JSP 后切换窗口即自动更新不用重启 Tomcat。配置完成后点击绿色三角启动。控制台出现Artifact is being deployed和Tomcat started on port(s): 8080就说明 Tomcat 拉起成功。这时候访问http://localhost:8080/能看到 IDEA 默认生成的 index.jsp 页面就说明你的工程构建没问题接下来把首页替换成登录页即可。3. 数据库设计三类表的字段、类型与关系3.1 图书管理系统的数据关系一句话说清楚这个系统的核心就一张关系一个用户可以借多本书一本书可以被多个人借过。所以至少三张表用户表、图书表、借阅记录表。很多同学只建前两张表借书用哪个用户、什么时候还、超期没有全靠内存里的变量这是答辩时的致命伤。我用的是以下 SQL 建表语句字符集统一utf8mb4collate用utf8mb4_unicode_ci。注意 MySQL 8.0 里utf8是utf8mb3的别名存 emoji 表情会报错所以直接写utf8mb4最省事。CREATE DATABASE IF NOT EXISTS book_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE book_db; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL, role TINYINT NOT NULL DEFAULT 0 COMMENT 0为普通用户1为管理员, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) NOT NULL UNIQUE, title VARCHAR(100) NOT NULL, author VARCHAR(50), publisher VARCHAR(50), total_count INT NOT NULL DEFAULT 1 COMMENT 总册数, available_count INT NOT NULL DEFAULT 1 COMMENT 当前可借册数, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB; CREATE TABLE borrow_record ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, book_id INT NOT NULL, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP, due_time DATETIME NOT NULL COMMENT 应还时间默认借书后30天, return_time DATETIME DEFAULT NULL, status TINYINT DEFAULT 0 COMMENT 0未还1已还, CONSTRAINT fk_borrow_user FOREIGN KEY (user_id) REFERENCES user(id), CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES book(id) ) ENGINEInnoDB;3.2 字段设计的取舍管理员怎么存、图书重复怎么处理数据库设计里最容易被追问的就是用户表里的 role 字段。有人会问为什么不用两张表分管理员和普通用户——课程设计阶段用一张表加 role 字段是对的因为权限模型只有两种角色再建表就是过度设计也增加了 JOIN 的复杂度。答辩时能说清这个理由很有加分效果。图书表里的total_count和available_count两个字段是借书并发控制的关键。每次借书时判断available_count 0然后减一还书时加一。如果只建一个总数不拆可用数两个人同时借同一本书的最后一册就会产生超借。我见过有同学把这两个数用页面传参的方式传过来更新比如传count5直接 update这是大忌——前端参数不可信后端永远要用 SQL 自带的数值计算。借阅记录表这里的status字段其实可以用return_time是否为 NULL 来代替但保留它会让查询更直观比如“查出所有超期未还的记录”WHERE status0 AND due_time NOW()一眼就能看懂。外键一定要加不加外键的孤儿数据在演示时看不到但写了“归还记录”功能的人一多脏数据就会冒出来。3.3 连接池还是 DriverManager课设怎么选JavaWeb 课本传统写法是DriverManager.getConnection()每次请求都新建一次数据库连接。它的好处是代码简单、好讲坏处是并发稍大一点就会报Too many connections。课程设计的并发量基本不会爆所以我建议直接用简单写法但要用一个工具类把连接获取和释放统一收口方便以后替换成连接池。package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/book_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4; private static final String USER root; private static final String PASSWORD 你的数据库密码; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, java.sql.Statement stmt, java.sql.ResultSet rs) { if (rs ! null) { try { rs.close(); } catch (SQLException ignored) {} } if (stmt ! null) { try { stmt.close(); } catch (SQLException ignored) {} } if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } } }CharacterEncodingutf8mb4这个参数很多人会漏掉。只设置serverTimezone不设置编码JSP 页面往里存中文没报错但查出来是问号问题就出在连接串上。另外注意 MySQL 8.0 的驱动类名是com.mysql.cj.jdbc.Driver一个字都不能错不像 5.7 那样是com.mysql.jdbc.Driver也能兼容。4. 核心代码实现登录、CRUD、分页与模糊搜索的完整流程4.1 三层架构拆解Servlet、Service、DAO 各自干什么图书管理系统的代码组织建议分包bean实体类、dao数据访问、service业务层、servlet控制层、util工具类、filter过滤器。JSP 只做展示任何System.out.println出现在 JSP% %里都算不合格。Service 层是容易省略的一层。如果你只写 Servlet DAO借书操作就需要在 Servlet 里写两步查图书是否可借、更新库存、插入记录。这三步一旦中途中途出错就会出现库存减了但记录没插入的情况。Service 层的作用是用事务把这三步包起来要么全成功要么全失败。package service; import dao.BookDao; import dao.BorrowRecordDao; import bean.Book; import bean.BorrowRecord; import util.DBUtil; import java.sql.Connection; import java.sql.SQLException; public class BorrowService { private BookDao bookDao new BookDao(); private BorrowRecordDao recordDao new BorrowRecordDao(); public boolean borrowBook(int userId, int bookId, int days) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 开启事务 Book book bookDao.getBookById(conn, bookId); if (book null || book.getAvailableCount() 0) { return false; // 连事务都不用回滚直接返回 } boolean updated bookDao.decreaseAvailable(conn, bookId); if (!updated) { conn.rollback(); return false; } BorrowRecord record new BorrowRecord(); record.setUserId(userId); record.setBookId(bookId); record.setDueTime(new java.util.Date(System.currentTimeMillis() days * 86400000L)); boolean inserted recordDao.insertRecord(conn, record); if (!inserted) { conn.rollback(); return false; } conn.commit(); return true; } catch (SQLException e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ignored) {} e.printStackTrace(); return false; } finally { try { if (conn ! null) conn.setAutoCommit(true); } catch (SQLException ignored) {} DBUtil.close(conn, null, null); } } }这段代码的关键在setAutoCommit(false)。MySQL 默认每条 SQL 自动提交借书业务有三条 SQL如果不关掉自动提交第二步更新成功、第三步插入失败时第一步已经提交了数据库里库存少了但借阅记录不存在。UPDATE book SET available_count available_count - 1 WHERE id ? AND available_count 0这个写法比先查再改要安全——它把判断和更新合并成一条原子 SQL状态变化的瞬间不会产生超借。days参数是从页面传来的默认 30但后端一定要限制范围防止有人传days9999。常见做法是服务端取Math.max(1, Math.min(30, days))。4.2 登录与 Session记住“不要再查一次数据库”登录页的表单提交到LoginServlet后正常流程是接收用户名密码 → DAO 查一条记录 → 比对密码 → session 存用户 → 跳转首页。这里有两个高频扣分点第一密码不能明文比对至少用 MD5 加盐存库。课程设计没强制要求你去接 BCrypt但你在答辩时能说出“密码校验用的是 MD5 加盐防止彩虹表碰撞”比直接明文存储高一个档次。package servlet; import bean.User; import dao.UserDao; import util.MD5Util; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; WebServlet(/login) public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); String username req.getParameter(username); String password req.getParameter(password); if (username null || username.trim().isEmpty() || password null || password.isEmpty()) { req.setAttribute(msg, 用户名和密码不能为空); req.getRequestDispatcher(login.jsp).forward(req, resp); return; } UserDao dao new UserDao(); User user dao.findByUsernameAndPassword(username, MD5Util.md5(password)); if (user null) { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); return; } HttpSession session req.getSession(); session.setAttribute(loginUser, user); session.setMaxInactiveInterval(30 * 60); resp.sendRedirect(req.getContextPath() /book/list); } }req.getParameter(username)之后第一件事是判空和 trim不要直接拿去拼 SQL。会话里只存 User 对象页面里要显示用户名时用${sessionScope.loginUser.username}不要为了显示一个名字再去dao.findByUserId查一次。福利点在于session.setMaxInactiveInterval(30*60)——不设置这行Tomcat 默认会话超时是 30 分钟设置了等于把超时时间写得更明确答辩问“多久不操作会自动退出”时你不会答不上来。4.3 图书列表分页SQL 里的 LIMIT 参数怎么传才算聪明图书列表页是系统最常访问的页面不做分页的话数据量一多页面就卡。分页公式是pageSize 10currentPage从页面接收默认 1offset (currentPage - 1) * pageSizeSQL 里写LIMIT ?, ?。注意用PreparedStatement传参时LIMIT后面的两个参数在 MySQL 里是整型不能拼字符串不然某些版本会报语法错误。public ListBook findPage(int currentPage, int pageSize, String keyword) { String sql SELECT id, isbn, title, author, publisher, total_count, available_count FROM book WHERE title LIKE ? OR author LIKE ? ORDER BY id DESC LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { String like % keyword %; ps.setString(1, like); ps.setString(2, like); ps.setInt(3, (currentPage - 1) * pageSize); ps.setInt(4, pageSize); try (ResultSet rs ps.executeQuery()) { ListBook list new ArrayList(); while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setIsbn(rs.getString(isbn)); b.setTitle(rs.getString(title)); b.setAuthor(rs.getString(author)); b.setPublisher(rs.getString(publisher)); b.setTotalCount(rs.getInt(total_count)); b.setAvailableCount(rs.getInt(available_count)); list.add(b); } return list; } } catch (SQLException e) { e.printStackTrace(); return Collections.emptyList(); } }try-with-resources是 JDK 7 引入的写法Connection、PreparedStatement、ResultSet都实现了AutoCloseable出了 try 块自动关闭。这个写法好过手写finally关连接因为人总会忘记关ResultSet而连接泄漏的报错又特别恶心——数据库连接不会超时释放Tomcat 跑一晚上就挂。分页还要查询总条数SELECT COUNT(*) FROM book WHERE title LIKE ?然后计算总页数totalPages (totalCount pageSize - 1) / pageSize这个公式向上取整比Math.ceil更直观。4.4 新增与编辑图书的校验那些必填的坑新增图书的表单里isbn 是唯一键重复插入会抛DuplicateKeyExceptionMySQL 驱动会包装成 SQLIntegrityConstraintViolationException。前端做了ajax校验 isbn 是否重复当然最好但后端照样要兜底。我一般会在 DAO 里先SELECT id FROM book WHERE isbn ?查一次再加try-catch捕获数据库异常两层保险。新增图书的 Servlet 里请求参数进去后所有字符串都做空值判断并且调trim()去掉首尾空格。你永远不能假设用户在表单里输入的 isbn 恰好没有空格这种脏数据在你做“查重”功能时会让两条看似不同的书实际上是一本。4.5 过滤器统一处理登录校验和请求编码登录拦截不用在每一个 Servlet 里写if (session.getAttribute(loginUser) null) { response.sendRedirect(login.jsp); }这种重复代码——用 Filter 一次性解决。建议建两个过滤器的同学注意登录路径本身要放行不然会出现“未登录访问登录页结果被重定向到登录页”这种循环。package filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; WebFilter(/*) 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); String uri request.getRequestURI(); // 放行登录页、登录接口、静态资源 if (uri.endsWith(login.jsp) || uri.endsWith(/login) || uri.contains(/css/) || uri.contains(/js/)) { chain.doFilter(req, resp); return; } if (session null || session.getAttribute(loginUser) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }编码过滤器也在这个阶段统一处理request和response都设置 UTF-8。千万不要在 JSP 页面里用meta charsetgbk或者pageEncodingGB2312你永远不知道用户提交的中文是哪个编码来的统一 UTF-8 是唯一不折腾的路线。5. IDEA 运行课设项目的常见问题与排查5.1 问题一一运行就报java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver现象Tomcat 启动正常访问页面时调数据库的接口就直接 500控制台打印找不到驱动类。原因把 jar 包放进了src/lib目录或者用 Project Structure 添加的依赖IDEA 编译期知道这个驱动存在但 Tomcat 运行期不会把项目里的依赖库自动加到 WEB-INF/lib。解决把 mysql-connector-java-8.0.x.jar 复制到web/WEB-INF/lib下然后在 Project Structure 里确认 Artifact 的 Output Layout 里有这个 jar。复制过后一定要 clean Tomcat 的部署目录File → Project Structure → Artifacts → 点一下项目 → 双击右侧 jar 加到左侧或者直接删掉 Tomcat 部署包重新部署。这个坑的特点是代码检查一切正常但运行时报缺类我当年在这个问题上耗了一下午后来查了 Tomcat 文档才知道 WEB-INF/lib 才是运行时类加载路径的默认规则。5.2 问题二数据库连接报错Public Key Retrieval is not allowed现象连接串写对了用户名密码也对了但 MySQL 8.0 首次连接时抛出Public Key Retrieval is not allowed。原因MySQL 8.0 默认使用 caching_sha2_password 认证方式客户端第一次连接需要拿服务器的公钥来加密密码而 JDBC 驱动为了保护安全默认不自动获取。解决在连接串上加allowPublicKeyRetrievaltrue这是最直接的办法。如果想更严谨可以建一个专用账号并指定 mysql_native_password 认证方式。课程设计直接用参数最省事但答辩时能说出“这是为了兼容 MySQL 8.0 的认证机制”就说明你真正理解了连接串每个参数的作用。同理serverTimezoneAsia/Shanghai不加就会报时区错误这两个参数是 MySQL 8.0 项目的标配。5.3 问题三Tomcat 10.x 跑老代码javax.servlet全包报红现象下载了最新的 Tomcat 10.1项目里所有import javax.servlet.http.HttpServlet都找不到IDEA 提示Package javax.servlet does not exist。原因Tomcat 10 开始把 Java EE 的包名从javax.*迁移到jakarta.*这是 Oracle 和 Eclipse 基金会之间的商标和治理问题代码层面就是改了个包名。解决最省事的是下载 Tomcat 9.0.x。除非你想顺手把代码从 javax 改成 jakarta 练手否则课设不要给自己加这个负担。IDEA 里的Application server配置改一下路径再加上Add Configuration里之前配置的 Tomcat 服务器把它替换掉即可。这个问题的判断技巧是编译报错明确指向javax.servlet这个包名而在 Tomcat 10 之前的版本里从来没出现过这种报错。5.4 问题四中文乱码所有从数据库查出的书名显示为???现象JSP 页面里meta charsetUTF-8设置了数据库表也用了utf8mb4但浏览器里全是问号。原因三层编码不统一。第一层JSP 页面本身要用pageEncodingUTF-8第二层Servlet 里request.setCharacterEncoding(UTF-8)要在读取表单参数之前调用第三层数据库连接串里必须有characterEncodingutf8或utf8mb4参数。这三层缺一不可。解决把这三处分别补上之后清空数据库重建表。如果你已经面向???插入了脏数据就算改了配置也显示不出来因为库里存的就是问号字符只能清表重来。这是血泪经验——改完编码设置记得先TRUNCATE再测试不要直接拿已有数据验证。5.5 问题五项目导入电脑后编译可以但运行报 404现象工程从 U 盘拷到另一台电脑IDEA 里打开能编译但启动后访问首页 404。原因导入工程时没有正确配置 Artifact。常见的是 IDEA 把原来的 Artifact 配置丢了或指向了旧路径Tomcat 部署的时候找不到可运行的应用上下文。解决打开File → Project Structure → Artifacts把原来项目里target或out目录下生成的 exploded war 删掉点加号重新加一个 Web Application Exploded然后回到Run Configuration → Deployment里把旧的 Artifact 移除、重新添加。这个坑在教室电脑和学生笔记本之间来回拷贝项目时极高发始终要记得Artifact 是 IDEA 的配置不是工程文件的一部分换了机器就要重建。6. 答辩之前把这些细节改掉你的评分能上一个档次6.1 SQL 注入检验PreparedStatement 和字符串拼接的区别答辩老师最常问的一句话是“你这个查询是怎么防 SQL 注入的” 翻车的回答是支支吾吾。安全的回答是所有涉及动态参数的 SQL 都用PreparedStatement用?占位符传参让 JDBC 驱动帮你转义特殊字符。你要真正理解为什么SELECT * FROM book WHERE title keyword 是不安全的——用户输入 OR 11之后拼接成的 SQL 就变成了WHERE title OR 11恒为真整张表的数据全出来了。你在写代码时强制自己不要用字符串加号拼 SQL。这个习惯带到 Spring Boot 的 MyBatis 里就是#{}和${}的区别现在养成肌肉记忆比以后补救容易得多。6.2 用 JSTL EL 替换 JSP 里的 Java 代码块如果 JSP 里到处都是% %和% for %那它不是一个合格的 JavaWeb 课设。熟练使用c:forEach、c:if、fn:contains是“会做”和“做得好”的分水岭。% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfn urihttp://java.sun.com/jsp/jstl/functions % table tr thISBN/thth书名/thth作者/thth可借数/thth操作/th /tr c:forEach items${page.list} varbook varStatusstatus tr td${book.isbn}/td td c:choose c:when test${fn:contains(book.title, Java)} b stylecolor:blue${book.title}/b /c:when c:otherwise${book.title}/c:otherwise /c:choose /td td${book.author}/td td${book.availableCount}/${book.totalCount}/td tda hrefbook/detail?id${book.id}详情/a/td /tr /c:forEach /table${page.list}里的page是 Servlet 里req.setAttribute(page, pageData)传进来的对象pageData里封装了list、totalCount、currentPage、pageSize。这套 EL 表达式的语法你需要熟到不用查表——它是整个 JavaWeb 课设最常被考核的知识点。6.3 事务边界再检查借书还书有没有可能产生脏数据最后再顺着代码走一遍事务流。借书检查 available_count → 减一 → 插入 borrow_record三步同一个事务。还书update borrow_record 的 return_time 和 status → book 表 available_count 加一同样是两步事务。你要保证手动调用Connection.setAutoCommit(false)和finally里的setAutoCommit(true)——如果忘了恢复自动提交连接池回收后这个连接再被拿到时还是非自动提交模式很隐蔽的翻车现场。给答辩老师看的借书流程用文字描述就是请求到 BorrowService → 开启事务 → 查书 → 判断可借数 → 扣减库存 → 写借阅记录 → 提交事务任何一步失败都回滚。这套话术比写满注释更有说服力。经验之谈课程设计不是要你发明新技术而是把你学过的知识点在一个完整场景里串起来。我最后会把 main 方法也删掉——让项目只能从 Tomcat 启动没有入口类的课设才是纯正的 JavaWeb 课设。这个项目做完以后你再去看看 Spring Boot 里的Transactional声明式事务和原生 JDBC 事务的区别会发现一切都是从这三张表和一行setAutoCommit(false)开始的。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

RFBNET电力巡检无人机航拍:目标检测框架、模型训练与先验框调优实战 2026/9/28 16:03:07

RFBNET电力巡检无人机航拍:目标检测框架、模型训练与先验框调优实战

简介:基于RFBNET的无人机航拍电力设施异常检测项目,面向毕业设计、课程设计与项目开发场景,完整提供Python源码与配套文档。方案在SSD顶部组装轻量级RFB模块构建检测网络,可对电力杆塔、输电线上的锈蚀、堆放杂物、绝缘子破损及异…

阅读更多 →
C#+asp.net+SQL Server网上选课系统源码解析与部署避坑指南 2026/9/28 16:03:07

C#+asp.net+SQL Server网上选课系统源码解析与部署避坑指南

简介:这是一份基于C#、ASP.NET与SQL Server的网上选课系统毕业设计/课程设计全套资源,面向需要完成管理系统开发的高校学生和初入.NET方向的开发者。资源包内含项目全套源码、数据库及完整文档,共69个文件,其中以32个C#源文件&…

阅读更多 →
大语言模型落地基础:从显存约束到推理全流程实战 2026/9/28 16:03:07

大语言模型落地基础:从显存约束到推理全流程实战

1. 这不是教科书里的“大语言模型基础”,而是我带三届实习生跑通LLM落地时反复撕掉的讲义“第三章-大语言模型基础”——看到这个标题,你脑子里是不是立刻浮现出那种密密麻麻堆满公式、动辄引用2017年Transformer原始论文、最后用“综上所述”收尾的PPT&…

阅读更多 →
高光谱遥感影像分类实战:从预处理到模型评估的完整技术路径 2026/9/28 16:03:07

高光谱遥感影像分类实战:从预处理到模型评估的完整技术路径

简介:基于Python实现的高光谱遥感影像识别与分类项目,面向毕业设计、课程设计与项目开发场景,适合需要完成遥感图像分类课题的学生或研究者。资源围绕高光谱数据“休斯现象”展开,提出了基于波段组合(2D)2PCA的降维方法&#xff0…

阅读更多 →
海思3798mv310机顶盒刷机避坑指南:保留语音遥控器的关键分区操作 2026/9/28 16:03:07

海思3798mv310机顶盒刷机避坑指南:保留语音遥控器的关键分区操作

1. 项目概述:这不是一次普通刷机,而是一场对硬件底层逻辑的精准外科手术华为EC6110-M机顶盒,表面看是台普通IPTV终端,但拆开后你会发现它藏着一颗海思3798mv310芯片——这颗SoC在2017年前后被大量用于中高端安卓电视盒子&#xff…

阅读更多 →
ArkTS状态管理实战:@State/@Prop/@Link用法与避坑指南 2026/9/28 16:03:01

ArkTS状态管理实战:@State/@Prop/@Link用法与避坑指南

做鸿蒙应用开发这段时间,我最大的感受是:凡是写过几行ArkTS页面的人,八成都在状态管理上栽过跟头。特别是State/Prop/Link这三个装饰器,官方文档写得很简洁,但真正上手之后,会发现一堆文档里没写明白的细节…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉