资讯动态

图书管理系统课程设计全攻略:从ER图到建库避坑指南

发布时间:2026/10/10 12:11:48 来源:尧图企业网站定制
简介面向计算机专业学生的数据库课程设计任务书选题为图书管理系统内容完整覆盖设计全流程。文档包括需求分析、概念结构设计、逻辑结构设计、物理结构设计和编码五个核心环节明确学生模块借阅、续借、归还、查询与管理员模块图书和学生增删改、借阅确认的功能要求并给出借书数量与期限等业务规则。针对设计部分任务书要求使用PowerDesigner建立业务模型、绘制E-R图、转换为关系模式并规范化同时完成索引、视图及SQL语句设计强调代码注释不少于三分之一。此外还提供了推荐参考资料与进度安排。资源为单份doc文档大小48KB共3页内容精炼可作为课程设计任务书模板或设计思路对照。已有2737人学习适合需要完成数据库课程设计、尤其是图书管理系统方向的学生参考。1. 先说清楚图书管理系统课程设计到底要交什么每次到课程设计验收前总能看到一批人抱着电脑和打印店来回跑那本《数据库课程设计--图书管理系统.doc》还没成型数据库里的表已经改得连自己都不认识。图书管理系统作为数据库课程设计里最常被选中的题目考验的不是你写过多少页面而是你是否能把需求、表结构、界面和文档四件事拧成一股绳。这篇内容专门说清这条绳怎么拧从需求分析讲到建库从界面层讲到答辩顺便把那些让人翻车的细节一个个拆开。适合正在赶课程设计的人也适合想拿这个题目练手数据库基本功的初学者。2. 需求分析与概念模型先画对读者、图书和借阅记录的线很多人打开 Navicat 直接建表表建到一半才发现少字段、多关联最后只能清库重来。做图书管理系统第一步不该是写 SQL而是把借书、还书这条主线的业务边界圈清楚。课程设计不需要你做一个完整的图书馆系统读者管理、图书管理、借阅归还、逾期管理这四块就够了别的功能都是给自己添乱。2.1 读者、图书、管理员、借阅记录谁在跟数据打交道我一般会先定义四个实体再给每个实体列出关键属性。这张表直接决定后面的建表语句值得花半小时认真写。实体关键属性业务规则读者读者编号、姓名、证件类型、证件号码、联系电话、可借额度、状态、注册日期可借额度默认 5 本状态区分正常和停用图书图书编号、ISBN、书名、作者、出版社、分类、定价、总库存、当前可借、上架日期、状态总库存必须大于等于当前可借数量状态区分上架和下架管理员管理员编号、用户名、密码哈希、姓名、角色、最近登录时间用户名唯一密码不能存明文借阅记录借阅编号、读者编号、图书编号、管理员编号、借出时间、应还时间、归还时间、续借次数、状态同一读者在借数量不能超过可借额度归还时间不能早于借出时间注意这里没有把罚款设计成独立实体。因为罚款金额可以从借阅记录的应还时间和归还时间算出来单独做一个罚款表反而会在删除、修改时带来数据一致性问题。课程设计里能用一个查询解决的就不要用一张表解决。借阅记录是全书的核心它的状态字段尤其重要。我习惯用 0 表示在借、1 表示已还、2 表示逾期而不是直接用时间判断。这样视图查询简单界面显示也直观。管理员为什么要放进借阅记录里因为答辩老师很可能问这本书是谁经手借出去的没有这个字段你就只能现补。2.2 ER图怎么画才不被扣分联系与基数ER 图是课程设计文档里的第一张图也是老师大概率会盯着看的一块。很多同学把读者和图书画成多对多然后中间挂一个借阅记录这在概念模型上是错的。借阅记录本身是联系集它把读者和图书联系起来。正确的画法是读者和借阅记录是一对多图书和借阅记录是一对多。为什么会画错因为把图书理解成了书名。在系统里一本书有多个副本你借的是某一册而不是书名这个抽象概念。但在课程设计的简化模型里图书表每一行代表一种书用总库存和当前可借表达副本数量所以借阅记录关联的是图书编号。这个简化设计在作业规模下完全成立但要能在文档里写清楚。联系参与实体基数说明借阅读者-借阅记录1 : N一个读者可以有多条借阅记录一条借阅记录只能属于一个读者被借图书-借阅记录1 : N一种书可以被借出多次每次借阅对应一条记录经办管理员-借阅记录1 : N一条借阅记录必有一个经办管理员画 ER 图时实体用矩形、属性用椭圆、联系用菱形这些标准画法在文档里不能省。属性要标出主键比如读者编号、图书编号用下划线区分。我见过有人把姓名当成主键画上去答辩现场直接被问倒。2.3 关系模式与主外键决策表把 ER 图转成关系模式时要顺手把范式检查一遍。借阅记录里不存读者姓名不存书名只存编号这就是第三范式的基本要求。很多人的借阅记录表里又有读者姓名又有书名查询倒是方便了但更新读者手机号时还要连带改借阅记录纯属给自己挖坑。关系模式用下划线标主键、星号标外键文档里可以这样列读者读者编号, 姓名, 证件类型, 证件号码, 联系电话, 可借额度, 状态, 注册日期图书图书编号, ISBN, 书名, 作者, 出版社, 分类, 定价, 总库存, 当前可借, 上架日期, 状态管理员管理员编号, 用户名, 密码哈希, 姓名, 角色, 最近登录借阅记录借阅编号, 读者编号*, 图书编号*, 管理员编号*, 借出时间, 应还时间, 归还时间, 续借次数, 状态外键策略要在建表前定好不然后面改表会很痛苦。我的决策表如下外键所在表删除策略更新策略理由读者编号借阅记录RESTRICTCASCADE已有借阅记录的读者不能被物理删除只能停用图书编号借阅记录RESTRICTCASCADE防止删书时把借阅历史一并抹掉管理员编号借阅记录RESTRICTRESTRICT管理员作为经办人必须存在这里最关键的决策是借阅记录对读者和图书都用 RESTRICT不用 CASCADE。原因后面避坑章节会细说但建表前记住一句话历史数据只能被标记删除不能被物理删除。3. 逻辑结构与物理建库把ER图落成能跑的SQL关系模式定好后建库其实是个体力活。但体力活里也有两个最常见的坑字符集选错导致中文乱码存储引擎选错导致事务不生效。这两个问题一般在整合界面时才爆发那时候再改表就是牵一发动全身。3.1 建库建表字符集与存储引擎的取舍数据库名字我用 library字符集统一用 utf8mb4排序规则用 utf8mb4_unicode_ci。utf8mb4 比老式 utf8 多支持 emoji 和生僻字图书标题里偶尔出现特殊字符时不会乱码。然后强制使用 InnoDB因为借书、还书必须依赖事务MyISAM 不支持事务和外键课程设计里用 MyISAM 是给自己埋雷。CREATE DATABASE IF NOT EXISTS library DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE library; CREATE TABLE reader ( reader_id INT UNSIGNED AUTO_INCREMENT COMMENT 读者编号主键, name VARCHAR(20) NOT NULL COMMENT 姓名, id_type TINYINT NOT NULL DEFAULT 1 COMMENT 证件类型1身份证2护照, id_no VARCHAR(18) NOT NULL COMMENT 证件号码, phone VARCHAR(11) DEFAULT NULL COMMENT 联系电话, borrow_limit TINYINT NOT NULL DEFAULT 5 COMMENT 最大可借数量, status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0停用, reg_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间, PRIMARY KEY (reader_id), UNIQUE KEY uk_id_type_no (id_type, id_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT读者表; CREATE TABLE book ( book_id INT UNSIGNED AUTO_INCREMENT COMMENT 图书编号, isbn VARCHAR(20) NOT NULL COMMENT ISBN, title VARCHAR(100) NOT NULL COMMENT 书名, author VARCHAR(50) NOT NULL COMMENT 作者, publisher VARCHAR(50) DEFAULT NULL COMMENT 出版社, category VARCHAR(20) DEFAULT NULL COMMENT 分类, price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 定价, total_count INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 总册数, available_count INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 当前可借数量, putaway_date DATE DEFAULT NULL COMMENT 上架日期, status TINYINT NOT NULL DEFAULT 1 COMMENT 1上架 0下架, PRIMARY KEY (book_id), KEY idx_title (title), KEY idx_category (category) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书表;这里几个参数要说清楚。reader_id用INT UNSIGNED因为读者数量到不了 42 亿上限借阅记录用BIGINT UNSIGNED因为每条借书记录都累积且还书之后不会物理删除增长比想象快。id_no定成 18 位是考虑身份证但证件类型是护照时可能不够所以实际课程设计里用VARCHAR(20)更稳妥。DECIMAL(10,2)表示最多 8 位整数加 2 位小数书价完全够用。DEFAULT CURRENT_TIMESTAMP需要 MySQL 5.6 以上版本现在的课程设计环境基本都满足。借阅记录表是外键最多的一张建表时要特别注意关联字段类型必须和外键主键完全一致。CREATE TABLE borrow_record ( borrow_id BIGINT UNSIGNED AUTO_INCREMENT COMMENT 借阅编号, reader_id INT UNSIGNED NOT NULL COMMENT 读者编号, book_id INT UNSIGNED NOT NULL COMMENT 图书编号, admin_id INT UNSIGNED NOT NULL COMMENT 经办管理员编号, borrow_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 借出时间, due_time DATETIME NOT NULL COMMENT 应还时间, return_time DATETIME DEFAULT NULL COMMENT 实际归还时间, renew_count TINYINT NOT NULL DEFAULT 0 COMMENT 续借次数, status TINYINT NOT NULL DEFAULT 0 COMMENT 0在借 1已还 2逾期, PRIMARY KEY (borrow_id), KEY idx_reader_borrow (reader_id, borrow_time), KEY idx_book_status (book_id, status), CONSTRAINT fk_borrow_reader FOREIGN KEY (reader_id) REFERENCES reader (reader_id) ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES book (book_id) ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT fk_borrow_admin FOREIGN KEY (admin_id) REFERENCES admin (admin_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT借阅记录表;due_time没有默认值它由代码或存储过程根据borrow_time 30天计算出来不能直接给DEFAULT CURRENT_TIMESTAMP否则每本书的应还时间都是借出那一刻逾期判断全乱。return_time默认 NULL 表示还没还还书时再填值这个空值语义要在文档里写清楚。3.2 约束与索引把脏数据挡在数据库门口课程设计的评审老师会翻建表语句看约束而不是只看界面。我在建表后加了三类约束唯一约束、检查约束、外键约束。唯一约束已经放在建表语句里证件类型加证件号码一起唯一这样同一证件类型下不会出现重复读者。ALTER TABLE reader ADD CONSTRAINT ck_reader_limit CHECK (borrow_limit BETWEEN 0 AND 20); ALTER TABLE book ADD CONSTRAINT ck_book_count CHECK (total_count available_count); ALTER TABLE borrow_record ADD CONSTRAINT ck_borrow_return CHECK (return_time IS NULL OR return_time borrow_time);检查约束有个需要记住的版本差异MySQL 8.0 才真正执行 CHECK 约束MySQL 5.7 解析但忽略它。如果你用的是 5.7这些校验只能在应用层或存储过程里做文档里要说明这一点答辩时被问数据库怎么保证归还日期不早于借出日期你才能答得上来。ck_book_count这条约束很实用它从数据库层面防止库存被扣成负数是借书流程的最后一道闸。索引方面不用贪多。借阅记录表上加一个idx_reader_borrow (reader_id, borrow_time)联合索引是因为系统最频繁的查询是某读者当前借了哪些书这个索引能让查询只用走一棵 B 树。如果只给 reader_id 建单列索引排序 borrow_time 时还要回表数据量小看不出来但答辩时讲联合索引的设计理由绝对是加分项。idx_book_status (book_id, status)对应某些书是否在借的查询。其他表只保留主键索引和必要的业务索引不要每列都加索引不仅浪费空间写入还会变慢。3.3 视图与存储过程给加分项留出位置很多课程设计只做到表和界面加两个视图和一个存储过程文档厚度和答辩底气立刻不一样。视图把复杂的关联查询封装起来界面层直接查视图就行而且能给老师展示你对外模式的理解。我常建两个视图当前借出视图和逾期未还视图。CREATE VIEW v_current_borrow AS SELECT r.reader_id, r.name AS reader_name, b.book_id, b.title, b.author, br.borrow_time, br.due_time FROM borrow_record br JOIN reader r ON br.reader_id r.reader_id JOIN book b ON br.book_id b.book_id WHERE br.status 0; CREATE VIEW v_overdue AS SELECT br.borrow_id, r.name AS reader_name, b.title, br.due_time, DATEDIFF(CURDATE(), br.due_time) AS overdue_days FROM borrow_record br JOIN reader r ON br.reader_id r.reader_id JOIN book b ON br.book_id b.book_id WHERE br.status 0 AND br.due_time CURDATE();视图的好处是屏蔽底层复杂连接同时可以限制用户能看到哪些列。比如 v_overdue 只暴露读者姓名、书名、逾期天数不暴露读者编号和管理员编号这就是一种简单的安全设计可以在文档里写上一句。存储过程我建议只写最核心的借书过程还书过程逻辑类似。借书过程要在一个事务里完成检查额度、检查库存、扣减库存、插入借阅记录四件事任何一步失败都回滚。DELIMITER $$ CREATE PROCEDURE sp_borrow( IN p_reader_id INT UNSIGNED, IN p_book_id INT UNSIGNED, IN p_admin_id INT UNSIGNED, IN p_days TINYINT ) BEGIN DECLARE v_limit TINYINT; DECLARE v_borrowed INT; DECLARE v_available INT; START TRANSACTION; SELECT borrow_limit INTO v_limit FROM reader WHERE reader_id p_reader_id AND status 1 FOR UPDATE; SELECT COUNT(*) INTO v_borrowed FROM borrow_record WHERE reader_id p_reader_id AND status 0; SELECT available_count INTO v_available FROM book WHERE book_id p_book_id AND status 1 FOR UPDATE; IF v_limit IS NULL OR v_borrowed v_limit THEN ROLLBACK; SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT 读者不存在、已停用或借阅额度已满; END IF; IF v_available IS NULL OR v_available 0 THEN ROLLBACK; SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT 图书不存在或库存不足; END IF; UPDATE book SET available_count available_count - 1 WHERE book_id p_book_id; INSERT INTO borrow_record (reader_id, book_id, admin_id, due_time, status) VALUES (p_reader_id, p_book_id, p_admin_id, DATE_ADD(NOW(), INTERVAL p_days DAY), 0); COMMIT; END$$ DELIMITER ;存储过程里的FOR UPDATE是行锁防止两个请求同时读到相同库存。SIGNAL SQLSTATE 45000是主动抛异常触发后事务回滚。p_days是借期天数参数课程设计里固定传 30 就行。调用方式就是CALL sp_borrow(1, 2, 1, 30)界面层一行调用完成整笔借书业务答辩时可以把存储过程的执行计划截图放进文档讲清锁和事务的关系。4. 界面层与数据访问答辩时最容易被问倒的环节数据库设计得再漂亮界面跑不通前面一切都白搭。答辩老师几乎都会打开系统点几下然后问一句这个借书操作在代码里是怎么实现的。这一章就是把数据库和界面的桥搭好。4.1 C/S还是B/S课程设计里的稳妥选型选型要看你剩多少时间。如果课程设计只要求做一个能演示的桌面程序C/S 是更稳妥的选择Java Swing 或者 C# WinForms 都行代码量小部署方便演示时不用担心浏览器兼容性和后端服务崩溃。B/S 架构界面更现代但要写前端、写后端、处理跨域和打包工作量至少翻一倍。维度C/SJava Swing JDBCB/S前端 后端框架代码量较小适合一个人完成较大前后端都要维护演示稳定性高不依赖容器中服务端口、静态资源路径都可能出错数据库连接方式JDBC 直连容易讲清连接池 ORM概念多容易答不清答辩提问风险集中在事务和 SQL可能被问框架原理、跨域、会话管理我的建议很直接除非老师明确要求网页界面否则就用 C/S。很多同学迷信 B/S 显得高级结果答辩时被问Spring Boot 和数据库是怎么连接的就卡住了。而用纯 JDBC你能把 Connection、PreparedStatement、ResultSet 每一步都讲明白这才是数据库课程设计要考察的能力。4.2 登录模块与权限控制一个粗糙SQL引起的翻车登录模块是每个系统都有的面子工程也是最容易出现低级错误的地方。最常见的翻车是把用户输入直接拼进 SQL用户名输入 or 11就能直接绕过密码登录。我见过真实课程设计里有人这么写答辩现场被老师试出来整个界面演示直接中断。正确做法是用 PreparedStatement 参数化查询密码存哈希而不是明文。Java 里大致是这样// 用户提交的用户名和密码 String sql SELECT admin_id, name, role FROM admin WHERE username ? AND password_hash ?; try (PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, hashPassword(password)); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { // 登录成功把 admin_id 和 role 存入会话 } else { // 用户名或密码错误 } } }PreparedStatement把参数当数据而不是 SQL 片段处理单引号和分号都失效这是从根上防止 SQL 注入。hashPassword我建议用 SHA-256 加随机盐但课程设计里至少要做到不存明文。如果用户名输入框还能查出 SQL 报错那基本上是 SQL 语句拼接的问题把日志里的 SQL 打印出来看一眼就知道错在哪。权限控制也要放在数据访问层做。界面按钮隐藏只是一种体验优化真正的权限判断要在查询数据库之前检查当前登录用户角色。比如还书操作前先查询管理员角色不是管理员就直接拒绝而不是只靠前端禁用一个按钮。课程设计做到这个粒度答辩时就能说出点东西。4.3 借书/还书/续借的事务边界账不平的根源借书在数据库层面至少做三步检查读者配额、扣减图书可借数量、插入借阅记录。这三步必须在一个事务里否则就会出现借阅记录有了但库存没扣这种账不平。很多同学用 JDBC 时默认没关自动提交每一条 SQL 执行完就自己提交导致前两步成功、第三步失败后无法回滚。我一般会在服务层手控事务代码逻辑如下Connection conn dataSource.getConnection(); try { conn.setAutoCommit(false); // 条件更新只有当可借数量大于 0 时才扣减 int rows bookMapper.decreaseAvailable(bookId); if (rows 0) { throw new BizException(图书库存不足); } borrowMapper.insert(readerId, bookId, adminId, dueTime); conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); conn.close(); }注意decreaseAvailable的 SQL 是UPDATE book SET available_count available_count - 1 WHERE book_id ? AND available_count 0把库存是否足够的判断直接放进 UPDATE 条件里而不要先 SELECT 再 UPDATE。这是典型的并发安全写法两个连接同时借最后一本书时数据库的行锁和条件更新能保证只有一个成功。如果之前一口气学了不少框架这个手写事务的细节反而更贴近数据库课程设计的核心。事务里不要做耗时操作比如调用外部接口、等待用户输入。连接持有锁的时间越长死锁概率越大。规模小的课程设计不需要调隔离级别默认的 REPEATABLE READ 够用。答辩时被问到多个读者同时借一本书怎么办把这段代码讲出来就过关了。5. 课程设计避坑清单五个让答辩现场冷场的细节这一章是从真实翻车现场里捞出来的经验。有些问题看着不起眼但恰好是答辩时老师最爱戳的地方。每条我都按现象、原因、解决三步写可以直接对照自己的系统排查。5.1 现象借书成功但库存没减界面提示借阅成功借阅记录也查得到但图书的可借数量纹丝不动。原因很可能是代码里先执行扣库存再插入借阅记录插入时因某个非空字段没填而报错异常被界面吞掉只有 INSERT 这步回滚了前面的 UPDATE 已经自动提交。解决方法是把所有数据库操作放进同一个事务并检查 UPDATE 的影响行数。影响行数为 0 说明条件没满足必须抛异常回滚绝不能在界面上显示成功。5.2 现象删除读者把历史借阅记录一起删了这是很多同学在建表时亲手埋下的雷。如果外键声明为ON DELETE CASCADE删除一个读者该读者所有的借阅记录都会被级联删除历史数据直接清零。答辩老师如果现场在数据库里执行删除操作你连恢复的机会都没有。正确做法是外键用ON DELETE RESTRICT删除时数据库会报错业务上改为把读者状态置为停用。历史数据只能标记删除不能物理删除这是数据库设计的基本素养也是课程设计里最容易考察的扣分点。5.3 现象还书日期总是比借书日期早界面日期控件没限制后端也没校验还书时手一滑选了昨天记录照样写进去。数据一旦脏了后面算逾期天数全是负数。我建议做三道拦截数据库加 CHECK 约束return_time borrow_time存储过程或服务层再校验一次界面上把还书日期控件的最大可选值设成今天。三层校验不是小题大做而是让你在答辩时能理直气壮地说这个数据在每一层都堵住了。5.4 现象并发借同一本书把库存借穿演示时不会出现并发但老师会问两个读者同时借最后一本书怎么办。如果代码是先查询可借数量再更新两个连接都能读到可借数量为 1然后各自执行 UPDATE库存就变成 -1。正确做法是把判断写进 UPDATE 条件里WHERE available_count 0让数据库的行锁替你解决竞态或者用SELECT ... FOR UPDATE锁住图书行直到事务结束。课程设计不要求你真正压测并发但能讲清锁和条件更新就比直接说没事强得多。5.5 现象答辩演示时数据一塌糊涂随手造的数据经不住细看书名是乱码分类不统一借阅日期跨了好几年老师随便搜一个书名就查不到。这本质上是没有演示脚本。我建议提前造一份固定数据写成一个reset_demo.sql答辩前执行一遍把系统恢复到已知的干净状态。数据量不用大5 个读者、10 本书、几条正常借阅记录和一条逾期记录就够了。演示顺序也固定先查书再借书然后还书最后查逾期。熟悉的数据能让你在操作时减少紧张也方便老师理解你的业务逻辑。6. 收尾技巧把文档结构做成你的答辩提词器课程设计最终交付的是一份 .doc 文档系统再漂亮文档结构混乱也会让评审印象分掉一截。文档不只是给老师看的更是你答辩时的提词器。我把自己的文档骨架固定为这几个部分需求分析、概念设计、逻辑设计、物理设计、界面说明、测试用例、总结。其中 ER 图放概念设计关系模式和建表语句放逻辑设计视图和存储过程放物理设计。6.1 文档骨架与验收前自查每张图表都要有编号和图题比如图 2-1 图书管理系统 ER 图表 3-3 借阅记录表结构。这是最基本的规范但很多课程设计文档里图没有编号、表没有标题评审老师看的时候还需要猜这是什么图体验很差。测试用例部分我建议用表格写输入、预期结果、实际结果、是否通过。不要多写10 个用例就够覆盖注册读者、上架图书、借书、还书、逾期查询、库存不足这些主线场景。验收前必做的一步是用一条 SQL 对账确保所有书目的库存数量跟借阅记录对得上SELECT t.book_id, t.title, t.total_count, t.available_count, t.lending_count FROM ( SELECT b.book_id, b.title, b.total_count, b.available_count, (SELECT COUNT(*) FROM borrow_record br WHERE br.book_id b.book_id AND br.status 0) AS lending_count FROM book b ) t WHERE t.total_count ! t.available_count t.lending_count;如果有查询结果说明有账目不平必须在验收前修正。这条 SQL 也值得写进文档作为数据一致性的自查工具。文档里还要有运行环境的说明包括 MySQL 版本、JDK 版本、JDBC 驱动版本。很多同学答辩时换了一台机器连接数据库报错就是因为环境说明没写清楚。把这个写进文档老师换机器验收时也不会卡在半路。说到最后我想起自己做这个题目时吃过的亏外键用 CASCADE演示前删了一个测试读者结果借阅记录跟着全没了对着白屏愣了五分钟。那次之后我养成了一个习惯所有破坏性操作前先备份所有外键从 RESTRICT 开始。数据库设计没有后悔药但提前堵住这些坑可以让你少吃不少后悔药。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑