ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java图书管理系统课程设计:数据库建模、JDBC事务与分层架构实战

Java图书管理系统课程设计:数据库建模、JDBC事务与分层架构实战 “图书管理系统”大概是我见过最两极分化的课程设计题目了。一方面它确实是Java课程设计里的常青树几乎每个学校的题目库都有它另一方面每年答辩季我都会看到一批学生熬夜到凌晨三点最后交上来一个“功能看似齐全、点开代码就崩”的半成品。很多人以为这个题简单——不就是图书的增删改查吗但实际做下来才发现登录逻辑、库存联动、借阅状态流转、超期计算任何一个环节没设计清楚后面全是补丁。这篇文章我打算从需求拆分讲到环境搭建、数据库建模、JDBC实操、核心功能实现、常见报错排查最后再聊答辩时怎么讲才能让评委觉得你“真懂”目标是让零基础的同学也能照着一步步做完并且知道自己每一步在做什么。1. 课程设计选题悖论图书管理系统看似简单为什么每年挂掉一半人1.1 课程设计和真实项目的差别评分点在“结构”不在“功能”先说一个反直觉的现象我见过的课程设计里功能做得最全的那批人分数往往不是最高的反而是那些功能朴实、但代码层次清楚的人拿了优秀。原因很简单。课程设计的评分老师一天要审几十份作业他没法真的把你每个按钮都点一遍。他看的是代码结构是否分层、异常是否处理、数据库设计是否合理、文档能不能说清楚你的思路。一个三层架构清楚、注释到位、会在借书时判断库存的项目哪怕只有三个功能老师也会觉得“这个学生是理解了的”。反之你把所有逻辑全塞在“界面类”里一个类三千行老师翻两页就想关了。所以你在动手之前先摆正心态这不是一个“把功能堆出来”的任务这是一个“证明你理解Java核心特性”的任务。面向对象、封装、DAO模式、JDBC事务、SQL与集合的转换这些才是评分表上真正扣分和加分的地方。1.2 需求范围拆解最小可用版本到底包含哪几块很多同学一上来就想着“我要做一个完整的系统”于是列了十几个功能做到第八个已经开始烦躁最后草草收尾。我建议你先做减法。图书管理系统的核心业务流转其实只有一条线管理员登录 → 管理图书 → 管理读者 → 处理借书还书 → 统计罚款。围绕这条线我把功能分成三档基础必做及格线管理员登录、图书信息的增删改查、读者信息的增删改查、借书功能、还书功能。建议做加分项模糊搜索、分页展示、借阅记录查询、超期罚款自动计算、密码MD5加密。有余力再碰亮点读者自助注册、排行榜、图表统计、Excel导出、批量导入。我见过很多零基础的同学栽在一个地方想一口气全做。结果每个功能都做成了“一个按钮弹个窗”数据库表没设计好就硬写代码后面越写越乱。正确的做法是先搭好骨架把基础必做跑通再一个一个加建议项。你每加一个功能都要回头看看“这个功能需不需要改表结构需不需要动DAO层”想清楚再动笔。2. 技术选型与开发环境控制台、Swing还是Spring Boot先想清楚再说2.1 不同技术栈的对比从答辩效果出发做选择每次课设答疑问得最多的就是“老师我到底用Swing还是用Spring Boot”这个问题没有一个万能答案主要看你手里有多少时间、你对哪个更熟。我做了一张对比表你可以直接对号入座技术栈上手难度工作量答辩观感适合哪类人纯控制台低小差老师会觉得太简陋只剩两三天、实在没时间Java Swing JDBC中中中界面偏老但逻辑清楚大二、只学过Java基础JavaFX JDBC中高中中上界面现代对Java根底有点信心的Spring Boot Thymeleaf中高较大高接近真实项目大三大四、学过框架Spring Boot Vue前后端分离高大高有前后端基础、时间充裕这里要泼一盆冷水不要为了答辩炫技去选一个你一个月学不完的技术栈。我见过不少同学跟风选Spring Boot Vue最后后端接口写了一半前端调不通临近答辩才回头问“能不能改成Swing”。说实话如果你们课程只教到Java SESwing或者JavaFX已经足够拿高分了。老师想看到的是“你会写类、会封装、会用JDBC”不是“你会搭个花架子”。如果让我推荐零基础的最优解Java Swing MySQL JDBC。这四条线全部踩在课程大纲上代码量适中遇到问题网上资料也最好找。等你做完这个版本如果你还有精力再把某个模块用Spring Boot重写一遍答辩时跟老师说一句“我对比过两种实现方式”效果反而更好。2.2 环境配置实操JDK、MySQL、IDE、连接驱动版本匹配选型定了环境必须先折腾明白。这里给一套我实操下来最稳的版本组合别乱升级JDK8或11都行不要装最新的17、21。不是不能用而是很多教材和网上文章默认用的是8你遇到报错去搜索时8的答案最多。MySQL8.0版本。注意8.0的驱动类和5.x不同连接参数也不一样很多老教程讲的是5.1的写法你照抄会报错。IDEEclipse或IntelliJ IDEA社区版都行。IDEA对新手更友好但内存占用大Eclipse启动快课程设计绰绰有余。JDBC驱动MySQL 8对应mysql-connector-j-8.0.x.jar别用com.mysql.jdbc.Driver要用com.mysql.cj.jdbc.Driver。如果你用Maven管理依赖pom.xml里这样写dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency如果你是用Eclipse/IDEA手工加jar包记得把mysql-connector-j-8.0.33.jar放进项目的lib目录然后右键“Add as Library”。这一步漏掉的话后面百分之百会报ClassNotFoundException。连接串也有讲究。MySQL 8时代最简单的写法是这样String url jdbc:mysql://localhost:3306/library?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8;这里的serverTimezoneAsia/Shanghai是刚需。不加它你会看到一个“The server time zone value”的英文报错不加characterEncodingutf8你往数据库里写入中文时十有八九会变成问号。提示如果你用的是IDEA注意右下角或顶部消息栏偶尔会提示“Setup JDK”不要忽略它否则你编译时能看到代码却找不到运行按钮。3. 数据库表结构设计五张表如何支撑借阅核心流转3.1 数据库设计的前置思考先画状态再定字段很多人建表是“想到什么加什么”图书表、读者表建完就开写写到借书功能时发现“哎我怎么知道这本书借出去了没”于是又回去加字段来回折腾。其实数据库设计有更省力的顺序先把业务流转画出来再定字段。图书借阅的核心流转是读者去借书 → 管理员登记 → 图书库存减一 → 生成借阅记录 → 到期还书 → 库存加一 → 如果超期则生成罚款所以系统至少要记录两个层面的东西实体信息图书、读者、管理员和过程信息借阅记录、罚款记录。实体信息解决“你是谁、这是什么书”的问题过程信息解决“这本书现在在谁手里、该不该还、罚了多少钱”的问题。你只要想明白这一点表结构就不会跑偏。另外还有一个特别容易踩的坑要不要把“当前借了几本书”作为读者表的一个字段我的建议是不要。借阅数量完全可以通过查询借阅记录表数出来你单独存一个字段还书、借书时还要手动改它一改漏就数据不一致。记住能算出来的数据尽量不存。3.2 五张核心表的字段定义与建表语句我直接给一份可以直接用的建表SQL。字符集统一用utf8mb4这是对中文最友好的编码。CREATE DATABASE IF NOT EXISTS library DEFAULT CHARACTER SET utf8mb4; CREATE TABLE admin ( admin_id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(32) ); CREATE TABLE book ( book_id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20), title VARCHAR(128) NOT NULL, author VARCHAR(64), publisher VARCHAR(64), price DECIMAL(10,2), category VARCHAR(32), stock INT DEFAULT 0, total INT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE reader ( reader_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) NOT NULL, phone VARCHAR(20), email VARCHAR(64), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE borrow_record ( borrow_id INT PRIMARY KEY AUTO_INCREMENT, book_id INT NOT NULL, reader_id INT NOT NULL, borrow_date DATE NOT NULL, due_date DATE NOT NULL, return_date DATE, status TINYINT DEFAULT 0, FOREIGN KEY (book_id) REFERENCES book(book_id), FOREIGN KEY (reader_id) REFERENCES reader(reader_id) ); CREATE TABLE fine ( fine_id INT PRIMARY KEY AUTO_INCREMENT, borrow_id INT NOT NULL, amount DECIMAL(10,2) NOT NULL, paid TINYINT DEFAULT 0, FOREIGN KEY (borrow_id) REFERENCES borrow_record(borrow_id) );几个字段设计的细节讲一下为什么这么写borrow_record.status用数字0表示借出、1表示已还、2表示逾期未还。用数字比用字符串省空间更重要的是程序里判断方便。你写if(rs.getInt(status) 1)比if(已还.equals(rs.getString(status)))要优雅得多。book.total表示图书总数stock表示当前可借数量。借书时stock-1还书时stock1而total不变这样你在统计“馆藏总量”和“当前可借”时都有数据来源。fine表里的paid用来标记罚款是否已缴纳。这个设计看似多余但没它你后期做“罚款统计”时会非常痛苦。所有外键关系在课程设计级别的项目里尽量保留。答辩时老师看见你有外键约束会明显认可因为很多学生的表是“各管各的”没有任何关系。4. JDBC连接MySQL的细节驱动加载、时区、事务一个都不能少4.1 数据库连接的正确姿势一个DBUtil工具类走天下课上老师讲JDBC的时候示例代码通常是把连接逻辑写在main方法里每查一次就写一遍DriverManager.getConnection。但课程设计里你要是这么写代码会炸开。正确做法是写一个工具类把“拿连接”和“关资源”封装起来全项目复用。我给你们一个我这些年用下来最顺手的模板import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/library?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException(MySQL驱动加载失败请检查jar包是否导入); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (stmt ! null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); } try { if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }这里有三个细节答辩时老师很喜欢问第一为什么用Class.forName加载驱动其实MySQL 8的JDBC驱动在Java 6以上可以自动注册不写也能连。但很多课程设计要求里明确写了要会手动加载驱动而且写上它可以让报错信息更直观——驱动jar没导入就直接抛“MySQL驱动加载失败”容易排查。第二为什么资源关闭要倒着关ResultSet依赖StatementStatement依赖Connection所以关闭顺序必须是先结果集、再语句、再连接。你要是先关了连接再关语句严格来说会有资源管理器报错虽然实际运行中不一定炸但这是个规范问题。第三为什么要把static块放在类里而不是每次连接前调用驱动只需要加载一次就够了放在静态块里类首次加载时执行后面所有连接都复用这次加载。这是Java类加载机制的基本应用答辩时主动提一句能看出你真的理解了static关键字。4.2 借书还书中的事务处理一个坑每年都有人踩我一直觉得课程设计阶段最该掌握的JDBC知识点就是事务。很多同学做借书功能时是这样写的先执行一条INSERT INTO borrow_record再执行一条UPDATE book SET stock stock - 1。表面看没问题但假如第一条SQL成功了第二条SQL因为某种原因失败了——比如库存字段写错、连接断开——就会出现“借阅记录有了库存没减”的脏数据。解决办法很简单把两步操作放进同一个事务里。JDBC里手动控制事务的代码如下Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交 // 第一步插入借阅记录 String sqlBorrow INSERT INTO borrow_record(book_id, reader_id, borrow_date, due_date, status) VALUES(?,?,?,?,0); PreparedStatement ps1 conn.prepareStatement(sqlBorrow); ps1.setInt(1, bookId); ps1.setInt(2, readerId); ps1.setDate(3, new java.sql.Date(System.currentTimeMillis())); // 设置应还日期默认借期30天 ps1.setDate(4, new java.sql.Date(System.currentTimeMillis() 30L * 24 * 3600 * 1000)); ps1.executeUpdate(); // 第二步扣减库存 String sqlStock UPDATE book SET stock stock - 1 WHERE book_id ? AND stock 0; PreparedStatement ps2 conn.prepareStatement(sqlStock); ps2.setInt(1, bookId); int rows ps2.executeUpdate(); if (rows 0) { throw new RuntimeException(库存不足借书失败); } conn.commit(); // 全部成功才提交 } catch (Exception e) { try { if (conn ! null) conn.rollback(); // 任何一步失败就回滚 } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); } finally { // 归还连接注意把事务状态复位 try { if (conn ! null) { conn.setAutoCommit(true); DBUtil.close(conn, null, null); } } catch (SQLException e) { e.printStackTrace(); } }注意这段代码里的两个巧思UPDATE book SET stock stock - 1 WHERE stock 0这一步我特意加了stock 0条件配合rows 0判断可以避免“库存为负”。而conn.setAutoCommit(false)到finally里再改回true是防止连接归还后被下一个使用者带着“非自动提交”的状态干活。这个细节很多人忽略池化连接复用时容易出诡异问题。答辩时你把这段讲明白基本就赢了。因为大部分同学的借书功能就是两条不带事务的SQL他们自己都没意识到会出什么问题。5. 核心业务代码逐个拆登录、增删改查、借书还书的实现逻辑5.1 数据访问层一个接口、一个实现类避免DAO代码满天飞很多零基础同学的代码是“Service里直接写JDBC”——这样写不是不能跑但你在Service里把PreparedStatement、ResultSet这些低级操作全堆出来代码会越来越难改。我做课程设计时习惯分两层DAO层只关心“怎么从数据库拿数据”对外提供findById、findAll、add、update、delete这类方法。业务层/Service层只关心“这个操作需要怎么做”比如借书业务是“先查库存再插入记录再扣库存”它只管调DAO不管SQL长什么样。以图书查询为例DAO层写一个接口public interface BookDAO { ListBook findAll() throws SQLException; Book findById(int bookId) throws SQLException; ListBook searchByTitle(String keyword) throws SQLException; boolean add(Book book) throws SQLException; boolean update(Book book) throws SQLException; boolean delete(int bookId) throws SQLException; }实现类里最核心的是那句“ResultSet转换成对象”的代码。我习惯单独抽一个方法private Book mapRow(ResultSet rs) throws SQLException { Book book new Book(); book.setBookId(rs.getInt(book_id)); book.setTitle(rs.getString(title)); book.setAuthor(rs.getString(author)); book.setPublisher(rs.getString(publisher)); book.setPrice(rs.getBigDecimal(price)); book.setCategory(rs.getString(category)); book.setStock(rs.getInt(stock)); book.setTotal(rs.getInt(total)); return book; }有的同学会问为什么不直接用rs.getString(title)绑定给界面因为那样的话界面类就依赖ResultSet而ResultSet是JDBC特有的类型你的UI层会变成“离不开数据库的植物人”。把它们转成普通的Book对象后界面、业务、数据三层互不干扰改SQL不会影响界面这就是分层的价值。5.2 借书还书完整流程两张表联动、库存校验、状态更新的代码骨架前面讲了事务代码这里我把借书的“业务层方法”完整串一遍你会发现所有操作都落在三个步骤上查库存 → 写记录 → 更新库存。public boolean borrowBook(int bookId, int readerId) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 1. 查库存 String sqlCheck SELECT stock FROM book WHERE book_id ? FOR UPDATE; PreparedStatement psCheck conn.prepareStatement(sqlCheck); psCheck.setInt(1, bookId); ResultSet rs psCheck.executeQuery(); if (!rs.next() || rs.getInt(stock) 0) { return false; } // 2. 插入借阅记录 String sqlInsert INSERT INTO borrow_record(book_id, reader_id, borrow_date, due_date, status) VALUES(?,?,?,?,0); PreparedStatement psInsert conn.prepareStatement(sqlInsert); psInsert.setInt(1, bookId); psInsert.setInt(2, readerId); long now System.currentTimeMillis(); psInsert.setDate(3, new java.sql.Date(now)); psInsert.setDate(4, new java.sql.Date(now 30L * 24 * 60 * 60 * 1000)); psInsert.executeUpdate(); // 3. 扣库存 String sqlUpdate UPDATE book SET stock stock - 1 WHERE book_id ? AND stock 0; PreparedStatement psUpdate conn.prepareStatement(sqlUpdate); psUpdate.setInt(1, bookId); psUpdate.executeUpdate(); conn.commit(); return true; } catch (SQLException e) { e.printStackTrace(); try { if (conn ! null) conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } return false; } finally { try { if (conn ! null) conn.setAutoCommit(true); DBUtil.close(conn, null, null); } catch (SQLException e) { e.printStackTrace(); } } }那个SELECT ... FOR UPDATE我解释一下这是“行级锁”防止两个管理员同时给同一本书办借书导致库存被减成负数。课程设计阶段老师可能不指望你会这个但你在答辩时提出来绝对是加分项。还书逻辑稍微反过来先查这条借阅记录是否存在且状态为“借出”然后更新return_date为今天把status改成“已还”再把库存加回去。超期罚款的计算很简单用今天的日期减去due_date超过一天就按某个金额累加long overdueDays (today.getTime() - dueDate.getTime()) / (24 * 3600 * 1000); if (overdueDays 0) { double fineAmount overdueDays * 0.5; // 每天0.5元 // 插入fine表 }做搜索功能时DAO层的核心就是一条带LIKE的SQLSELECT * FROM book WHERE title LIKE ? OR author LIKE ? ORDER BY book_id LIMIT ?, ?分页要注意LIMIT的偏移量是(page - 1) * pageSize不是page。很多同学第一页没问题第二页就少数据基本都是这里算错了。6. 从报错堆栈到问题定位课程设计期间最常见的五类坑6.1 ClassNotFoundException和SQLException的排查链路写课程设计这几天你大概率会碰上这么几个报错我按出现频率排个序直接把排查链路写给你们。以后遇到“红色异常”不要慌先看第一行英文。java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver这个报错90%的原因是jar包没导入1%是版本过老写错类名。排查方式进IDEA左侧的External Libraries或Eclipse的Referenced Libraries搜一下有没有mysql-connector-j这个包。没有就重新导入有的话再看你自己写的Class.forName里面的字符串是不是com.mysql.cj.jdbc.Driver而不是com.mysql.jdbc.Driver。java.sql.SQLException: The server time zone value ...这就是我前面说的serverTimezone参数漏了。在URL末尾加上serverTimezoneAsia/Shanghai即可。如果加了还报错检查你是不是在项目里同时导了旧版mysql-connector-java-5.x的jar包把老jar删干净。java.sql.SQLException: Access denied for user rootlocalhost密码错了或者用户名写错。去DBUtil里检查你的USER和PASSWORD是不是对得上。还有一种情况是MySQL 8默认的认证插件是caching_sha2_password但你的驱动版本太老这也会报Access denied解决办法是把驱动换成8.0以上版本。Public Key Retrieval is not allowed这是MySQL 8 Connector/J 8.0的一个经典报错。原因是为了安全驱动默认不自动获取服务器的公钥。最简单的解决办法是在URL上加上allowPublicKeyRetrievaltrue。java.sql.SQLException: Column xxx not found检查SQL语句里的列名和表结构是否完全一致。注意MySQL的列名是不区分大小写的所以问题一般出在拼写不是大小写。6.2 中文乱码、内存溢出、界面卡死等高频问题比报错更让人崩溃的是“程序没报错但结果不对”。中文乱码就是最典型的数据库里中文正常但Java程序读出来全是???。这通常涉及四个地方你逐个检查连接URL有没有characterEncodingutf8。数据库和表的字符集是不是utf8mb4建表语句里我写了别改。IDE的文件编码是否设置为UTF-8IDEA设置里搜File Encodings全改成UTF-8。如果你用控制台输出中文乱码那就是终端编码问题Windows下按WinR输入cmd执行chcp 65001切换UTF-8代码页再重启IDE或者直接在IDE的Run Configuration里加-Dfile.encodingUTF-8。还有几个我实际帮人调试时看到过很多次的问题Swing界面点“查询”卡死几秒再弹结果——这是把耗时操作放在事件调度线程EDT里跑导致的。课程设计数据量小时感觉不明显但查询慢的痕迹很丢分。解法是开个线程去跑数据库查询查完通过SwingUtilities.invokeLater回到界面更新。你不需要深究并发理论只要记住按钮监听器里不要直接写数据库代码。导出几千条数据时内存溢出报OutOfMemoryError——解法是分页查询再写文件不要一次性SELECT *塞进List再写。Java里一个对象存几千条数据本来就吃内存加上界面组件再占一份很容易炸。两个管理员同时给同一本书借书库存变成-1——这属于并发问题前面说的SELECT ... FOR UPDATE就是干这个的。课程设计答辩时老师如果问“多个人同时借书怎么办”你能说出这个方案就已经超出大部分人水平了。7. 答辩演示与评委提问让评委觉得你真正懂这个系统的技巧7.1 演示路径设计先把“加分功能”放前面答辩和讲课一样开头三分钟决定了评委对你是“优秀”还是“及格”的初判。我见过太多学生上来就演示“登录”而登录是所有系统都有的功能等于你把最平庸的东西放在最前面。我建议的演示顺序是先把建议做和亮点功能亮出来。比如你做的是模糊搜索 分页 超期罚款计算那就先输入一个不完整的关键词比如搜“三”瞬间显示分页结果然后演示一本超期的书还书时自动弹罚款金额。这一套走完评委心里已经默认你是“功能全面”的选手了。然后再回到“登录 → 图书管理 → 读者管理 → 借书还书”的主流程把基础环节平顺过一遍最后有时间再点一点代码里你觉得写得好的地方。演示时还要注意数据准备。提前在数据库里造好一批像样的数据十来本书、七八个读者、有一条已经超期的借阅记录。如果你的演示界面上全是空表评委手动输数据等你演示好感度会大打折扣。7.2 高频提问与标准应答从“怎么实现”到“为什么这样实现”答辩题库其实很固定我把出现频率最高的几个问题列一下你按下面的思路准备基本能覆盖80%的情况“你这个系统怎么防止SQL注入”答所有SQL操作都用PreparedStatement参数通过setString、setInt绑定不直接拼接字符串。PreparedStatement会由驱动程序对参数做转义把用户输入当作数据而不是SQL语句解析。如果能再补一句“字符串查询用LIKE模糊匹配时我会先把用户输入里的%和_转义掉”评委眼睛会亮。“图书表、读者表、借阅表之间什么关系”答图书和读者是多对多关系通过borrow_record表充当中间表实现。每一条借阅记录关联一个读者和一本图书同时记录了借出日期、应还日期、实还日期和状态。这里你站起来在黑板上画一下三张表连线划清楚这个题就稳过了。“借书和还书如果同时发生会不会出错怎么解决”答会。我在借书时对图书行加了FOR UPDATE锁同一本书的并发借书操作会被串行化。同时借书和还书两个操作放在一个事务里任何一步失败都会回滚不会出现记录和库存不一致。能答到这个深度基本不用发愁了。“你这个系统数据量变大了比如到十万本书会卡吗”答目前实现的查询都带条件过滤、分页不会一次性加载全表。如果数据量进一步增长可以考虑给title、author字段加索引也可以用连接池管理连接减少每次建立连接的开销。你不需要真去优化但能说出思路就行。“状态字段为什么用数字不用中文”答数字存储节省空间比较时不需要做字符串匹配。更重要的是数据库里中文状态可读性差一旦你改了业务规则就要刷数据而用数字只要在Java的枚举或常量的映射里改对应关系即可。这里可以顺带提一句“修改一处全局生效”让老师感受到你理解了枚举常量的好处。最后我还是想啰嗦一句也是带过这么多届学生后最深的一个感受课设拉开差距的时间点从来不是最后三天而是第一周你肯不肯静下心把表结构画出来、把每个按钮背后的方法列出来。你要是现在还没动手别急着开IDE先拿张白纸把“读者借书”这个动作从头到尾写一遍——从点哪个按钮到调用哪个Service方法再到改哪几张表——写清楚了你就会发现代码反而没那么难写了。我见过太多“功能做得花里胡哨但数据库结构一塌糊涂”的项目也见过“只有三个功能但分层清晰、异常处理到位”的作业拿了优秀你要做哪一种从打开IDE写下第一行CREATE TABLE的时候就已经决定了。
返回列表