简介本资源是一份面向数据库设计初学者与课程实践者的《用户需求定义》教学文档聚焦StayHome连锁视频租赁系统的业务建模与需求分析。文档系统梳理了分公司、员工、录像、会员、租借五大核心实体的数据结构与完整性约束详述数据录入、更新、删除及高频查询等26类事务操作并涵盖初始规模2万录像、2000员工、10万会员、增长规律、并发访问、安全权限、备份策略及合规要求等系统级定义是数据库需求分析与ER建模的典型范例。资源为单个PDF文件大小仅28KB内容精炼完整适合作为数据库原理课程作业参考、课程设计需求说明书模板或SQL建库前的需求梳理依据。目前已有66人学习下载内容覆盖从数据建模到性能指标的全链路需求描述可直接用于课程实践、毕业设计需求阶段交付或需求文档写作训练。1. 这不是一份PDF说明书而是一份能直接驱动数据库建模的用户需求黑匣子你手头这份《用户需求定义[定义].pdf》表面看是2013年陈新剑老师写的StayHome录像租赁系统需求文档但实际它是一份未经加工、保留原始业务语义的数据库建模黄金原料——不是教科书里的理想化ER图而是真实世界里“分公司要查某演员所有可租录像”“会员两年没租片就自动归档”“周五晚6–9点查询量翻倍”这种带着时间戳、带并发压力、带法律红线的硬需求。它不告诉你用MySQL还是Oracle但每一条“事务需求a–z”都是SQL语句的胚胎每一个“数据需求”字段都在暗示主键/外键/索引设计甚至“每天下午6–9点峰值查询10000次”这种描述直接决定了你该在rental表上建复合索引还是分区表。适合正在做课程设计、毕业设计或中小型企业数据库重构的工程师——尤其当你被甲方甩来一句“按业务逻辑来”而手里只有零散Excel和微信聊天记录时这份PDF就是你唯一能抓住的、有上下文、有量级、有边界的真实锚点。2. 从需求文本到实体关系三步拆解法还原业务本质2.1 抽取核心实体与属性拒绝照抄文字用“谁拥有什么”校验字段完整性不能把PDF里“分公司地址由街道、城市、州和邮政编码组成”直接当一个VARCHAR(255)字段塞进表里。真实建模中地址必须拆解为独立实体或结构化字段否则无法实现“列出给定城市的分公司”需求m的高效查询。我一般会这样处理-- 分公司表city字段单独建索引为需求m加速 CREATE TABLE branch ( branch_id CHAR(8) PRIMARY KEY, -- 如 BR000001非自增ID因需全局唯一且业务可读 branch_name VARCHAR(100) NOT NULL UNIQUE, street VARCHAR(100), city VARCHAR(50) NOT NULL, -- 关键此处建索引支撑需求m state CHAR(2), -- 美国州缩写如 WA postal_code VARCHAR(20), phone_lines TEXT -- JSON存储最多3行号码避免预留phone1/phone2/phone3冗余字段 ); -- 员工表employee_id全局唯一非branch_id内自增 CREATE TABLE employee ( employee_id CHAR(10) PRIMARY KEY, -- 全公司唯一如 EMP0000001 branch_id CHAR(8) NOT NULL, name VARCHAR(80) NOT NULL, position ENUM(manager,supervisor,staff) NOT NULL, -- 用ENUM而非VARCHAR约束非法值 salary DECIMAL(10,2), FOREIGN KEY (branch_id) REFERENCES branch(branch_id) );提示PDF中“每个分公司有个名称在全公司是唯一的”这句话直接否定了用branch_id作为自增INT的方案——因为业务要求名称唯一而ID只是技术标识。这里用CHAR(8)前缀数字更贴近现实如BR000001也方便后续报表打印。2.2 识别关系强度与基数用事务需求反推外键约束逻辑PDF里“每个分公司有若干名员工包括一个经理”不是模糊描述而是明确的1:N强关系 1:1角色约束。这意味着employee.branch_id是外键强制关联但“经理”不能仅靠positionmanager判断因为一个分公司可能有多个manager如临时代理。真实系统中应在branch表加manager_id CHAR(10)字段并设FOREIGN KEY指向employee.employee_id同时加CHECK约束确保该ID确属本分公司ALTER TABLE branch ADD COLUMN manager_id CHAR(10), ADD CONSTRAINT fk_manager FOREIGN KEY (manager_id) REFERENCES employee(employee_id), ADD CONSTRAINT chk_manager_in_branch CHECK (manager_id IS NULL OR manager_id IN ( SELECT employee_id FROM employee WHERE branch_id branch.branch_id ));同样“会员号对所有分公司都是唯一的而且可以在多个分公司使用同一会员注册号”PDF第1页说明member表是全局中心表rental表中的member_id必须直接引用它而非在各分公司库中重复存储——这是分布式架构下避免数据不一致的铁律。2.3 事务需求映射SQL操作类型把a–z清单变成DDL/DML检查表PDF第1页列出的a–z共26条事务需求本质是26个CRUD场景。我习惯用表格将其分类标注对应SQL类型及隐含约束需求编号操作类型对应SQL关键约束/陷阱a) 录入新分公司INSERTINSERT INTO branch (...) VALUES (...);branch_name必须UNIQUE且city不能为空支撑需求mf) 录入租借协议INSERTINSERT INTO rental (rental_id, member_id, video_copy_id, ...) VALUES (...);video_copy_id状态必须为available需在应用层或触发器校验k) 更新会员信息UPDATEUPDATE member SET address... WHERE member_id...;若修改member_id需同步更新所有rental表记录——绝对禁止ID必须不可变s) 列出某会员全部租借详情SELECTSELECT r.*, v.title, v.genre FROM rental r JOIN video_copy vc ON r.video_copy_idvc.copy_id JOIN video v ON vc.video_idv.video_id WHERE r.member_idM000001;必须JOIN三层且video_copy表需有video_id外键否则无法关联片名注意需求z“列出每个分公司可能的租金收入”看似简单实则暗藏陷阱——“可能的租金收入”指所有statusavailable拷贝的daily_rental_fee之和不是历史已收金额。这意味着不能只查rental表必须聚合video_copy状态且需考虑video_copy表中daily_rental_fee字段是否允许NULLPDF未明说但业务上绝不应为空。3. 系统定义参数落地把“大约2000名员工”变成建表时的容量预判3.1 初始数据规模决定存储引擎与字符集选择PDF第2页明确给出初始规模“约2000名员工”“100000名会员”“400000盘录像拷贝”。这不是估算是建表前必须填入的容量基线employee表2000行 → MyISAM或InnoDB均可但考虑到后续需事务如员工离职时级联更新租借记录必须选InnoDBmember表100000行 →member_id若用CHAR(8)索引体积远小于BIGINT优先CHAR前缀索引video_copy表400000行 → 单表超40万行且高频查询需求d每天10000–20000次必须分区按statusavailable/unavailable/lost哈希分区将热数据available集中冷数据隔离。-- video_copy表分区示例MySQL 5.7 CREATE TABLE video_copy ( copy_id CHAR(12) PRIMARY KEY, video_id CHAR(10) NOT NULL, status ENUM(available,rented,lost,damaged) NOT NULL DEFAULT available, daily_rental_fee DECIMAL(6,2) NOT NULL, ... ) PARTITION BY HASH (CASE status WHEN available THEN 1 WHEN rented THEN 2 ELSE 3 END) PARTITIONS 3;血泪经验曾见团队把video_copy按video_id范围分区结果热门影片拷贝全挤在同一个分区导致热点分区IO打满。PDF里“每天下午6–9点查询量翻倍”提醒你分区键必须与查询模式强相关而不是随意选主键。3.2 增长速率倒推TTL策略与归档机制PDF第2页“数据库增长速度”部分是DBA的作战地图每月新增100部新片 × 20份拷贝 2000行/月 → 2.4万行/年每月删除100条过期拷贝记录 →需DELETE而非TRUNCATE因涉及历史统计每天新增5000条租借记录 →年增182万行两年后需清理PDF明确“录像出租记录在创建两年后被删除”。这意味着rental表必须设created_at DATETIME NOT NULL并建立INDEX(created_at)绝不能依赖应用层定时任务删数据——高并发下易锁表。应使用MySQL事件调度器EVENT每日凌晨执行-- 创建自动清理事件 CREATE EVENT ev_cleanup_rental ON SCHEDULE EVERY 1 DAY DO DELETE FROM rental WHERE created_at DATE_SUB(NOW(), INTERVAL 2 YEAR) LIMIT 10000; -- 分批删除避免长事务3.3 性能指标转化为索引与缓存配置PDF第3页性能要求“高峰期单记录搜索5秒”“多记录搜索10秒”。这不是服务器配置问题是索引设计的KPI需求c“查询指定录像的情况”每天5000–10000次→video表必须有INDEX(title)且title字段用utf8mb4_unicode_ci排序支持中文片名模糊查需求p“分类列出某分公司录像”→video_copy表需INDEX(branch_id, status, genre)复合索引覆盖WHEREORDER BY需求v“列出每个分公司每种录像的数量”→ 此类GROUP BY统计必须走索引*不能SELECT后在内存聚合因此video_copy表需INDEX(branch_id, genre)。玄学时刻PDF写“每天下午6–9点是高峰时期”但没说这3小时占全天查询量多少。我一般按70%流量集中在3小时估算即QPS (10000×0.7)/10800 ≈ 0.65看似不高但rental表JOINvideo_copyvideo三表时若无覆盖索引单次查询可能扫全表——这就是为什么需求d“查询某盘录像某份拷贝”必须有INDEX(video_id, copy_id)而非只建copy_id主键。4. 安全、备份与合规把PDF里的“口令保护”变成可执行的SQL权限脚本4.1 基于角色的最小权限分配用PDF“主管、经理、监理”定义数据库角色PDF第3页安全性要求“每个员工分配到特定用户视图的数据库访问权限主要是主管、经理、监理、助理和采购员”。这不是喊口号是必须落地的GRANT语句清单-- 创建角色MySQL 8.0 CREATE ROLE branch_manager, supervisor, staff, procurement; -- 经理可查本分公司所有数据可更新员工/录像状态 GRANT SELECT, UPDATE ON stayhome.branch TO branch_manager; GRANT SELECT, INSERT, UPDATE ON stayhome.employee TO branch_manager; GRANT SELECT, UPDATE ON stayhome.video_copy TO branch_manager; -- 可改status GRANT SELECT ON stayhome.rental TO branch_manager; -- 监理只查本分公司员工不可改数据 GRANT SELECT ON stayhome.employee TO supervisor; GRANT SELECT ON stayhome.video_copy TO supervisor; -- 采购员只管录像订单不碰租借数据 GRANT SELECT, INSERT ON stayhome.order TO procurement; GRANT SELECT ON stayhome.video TO procurement;关键细节PDF强调“员工只能在适合他们完成工作的需要窗口中看到需要的数据”这意味着不能给角色授DATABASE级权限必须精确到TABLECOLUMN。例如staff角色连salary字段都不能SELECT需建视图过滤CREATE VIEW staff_employee_view AS SELECT employee_id, name, position, branch_id FROM employee; GRANT SELECT ON stayhome.staff_employee_view TO staff;4.2 备份策略必须匹配PDF的“每天半夜12点备份”硬要求PDF第3页“数据库必须在每天半夜12点备份”是SLA级承诺不能靠mysqldump手动执行。我用automysqlbackup工具crontab固化# /etc/cron.d/mysql-backup 0 0 * * * root /usr/local/bin/automysqlbackup -c /etc/automysqlbackup.conf /var/log/automysqlbackup.log 21配置文件/etc/automysqlbackup.conf关键项CONFIG_mysql_dump_usernamebackup_user # 专用备份账号只授SELECT权限 CONFIG_mysql_dump_passwordxxx # 密码加密存储 CONFIG_backup_dir/backup/mysql # 独立磁盘非系统盘 CONFIG_rotation_daily7 # 保留7天满足“法律要求可追溯” CONFIG_gzipyes # 压缩节省空间PDF未提但必需避坑曾因备份账号密码明文写在crontab里被扫描泄露。现在一律用mysql_config_editor加密登录路径automysqlbackup调用mysql --login-pathbackup连接。4.3 合规性落地把“法律管理个人数据”转化为字段级脱敏规则PDF第3页“每个国家都有法律管理个人数据的计算机存储”结合“会员地址”“员工薪水”等字段必须实施动态数据脱敏DDMMySQL 8.0 可用CREATE FUNCTION隐藏敏感字段DELIMITER $$ CREATE FUNCTION mask_address(addr TEXT) RETURNS TEXT READS SQL DATA DETERMINISTIC BEGIN RETURN CONCAT(LEFT(addr, 3), ***, SUBSTRING_INDEX(addr, , -1)); END$$ DELIMITER ; -- 在视图中调用 CREATE VIEW member_safe AS SELECT member_id, name, mask_address(address) as address_masked, register_date FROM member;对salary字段采购员角色查询时返回FLOOR(salary/1000)*1000千元级精度既满足业务又降低泄露风险。5. 避坑PDF里埋着的5个致命陷阱与血泪解决方案5.1 现象按“片名顺序列出某分公司指定演员的录像”需求q查询极慢原因PDF中“主要演员名字以及扮演的角色”存为TEXT字段且未建FULLTEXT索引LIKE %张艺谋%全表扫描。解决拆分actor为独立表建立video_actor关联表并在actor.name建INDEX(name)CREATE TABLE actor ( actor_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, INDEX idx_name (name) ); CREATE TABLE video_actor ( video_id CHAR(10), actor_id INT, role VARCHAR(50), PRIMARY KEY (video_id, actor_id) ); -- 查询改写为JOIN速度提升10倍 SELECT v.title, v.genre, va.role FROM video v JOIN video_actor va ON v.video_id va.video_id JOIN actor a ON va.actor_id a.actor_id WHERE a.name 张艺谋 AND v.branch_id BR000001 ORDER BY v.title;5.2 现象会员两年没租片自动删除后租借历史报表断层原因PDF要求“会员两年没租借任何录像将删除该会员记录”但rental表仍保留旧记录导致LEFT JOIN member时出现NULL报表统计失真。解决不物理删除会员改为status ENUM(active,archived)并加last_rental_date字段ALTER TABLE member ADD COLUMN last_rental_date DATE, ADD COLUMN status ENUM(active,archived) DEFAULT active; -- 定时任务更新last_rental_date而非删记录 UPDATE member m JOIN (SELECT member_id, MAX(rent_date) as max_rent FROM rental GROUP BY member_id) r ON m.member_id r.member_id SET m.last_rental_date r.max_rent; -- 归档逻辑UPDATE member SET statusarchived WHERE last_rental_date DATE_SUB(NOW(), INTERVAL 2 YEAR);5.3 现象分公司经理更换时branch.manager_id更新失败并引发数据不一致原因PDF未说明经理变更是否需审计但业务上必须留痕。直接UPDATEmanager_id会导致历史责任无法追溯。解决建branch_management历史表每次任命新经理插入记录branch表只存当前IDCREATE TABLE branch_management ( id BIGINT PRIMARY KEY AUTO_INCREMENT, branch_id CHAR(8) NOT NULL, manager_id CHAR(10) NOT NULL, start_date DATE NOT NULL, end_date DATE, -- NULL表示现任 FOREIGN KEY (branch_id) REFERENCES branch(branch_id), FOREIGN KEY (manager_id) REFERENCES employee(employee_id) ); -- 当前经理取MAX(end_date)为NULL的记录5.4 现象video_copy.status从available改为rented时并发租借导致超租原因PDF中“状态指出一盘录像的某份拷贝是否可以出租”但未提并发控制。两个用户同时SELECT available再UPDATE必然超租。解决用SELECT ... FOR UPDATE加行锁或更优——用原子UPDATEUPDATE video_copy SET status rented WHERE copy_id VC000001 AND status available; -- 检查影响行数若为0则提示该拷贝已被租出5.5 现象按“分公司号排序列出每种录像数量”需求v结果与手工统计不符原因PDF中“录像的种类有动作、成人、儿童、恐怖、科幻”但video.genre字段未设CHECK约束录入时出现terror、horror混用GROUP BY时分裂统计。解决强制枚举迁移旧数据ALTER TABLE video MODIFY COLUMN genre ENUM(action,adult,children,horror,scifi) NOT NULL; -- 批量修正脏数据 UPDATE video SET genre horror WHERE genre IN (terror,fear);6. 验证需求闭环用PDF原文逐条生成测试用例与SQL断言6.1 构建需求追踪矩阵让每一行PDF都对应可执行的验证SQL不能只靠人工测试我把PDF的a–z事务需求和m–z查询需求全部转为自动化验证用例。以需求n“按照员工的名字顺序列出指定分公司的员工名称、职位、薪水”为例-- 测试用例验证需求n -- 准备数据 INSERT INTO branch (branch_id, branch_name, city) VALUES (BR000001, Seattle Downtown, Seattle); INSERT INTO employee (employee_id, branch_id, name, position, salary) VALUES (EMP000001, BR000001, Zhang San, manager, 8500.00), (EMP000002, BR000001, Li Si, supervisor, 6200.00); -- 断言SQL返回2行按name升序且salary精度为2位小数 SELECT name, position, salary FROM employee WHERE branch_id BR000001 ORDER BY name ASC; -- 预期结果断言Python pytest示例 def test_requirement_n(): rows execute_sql(SELECT name, position, salary FROM employee WHERE branch_idBR000001 ORDER BY name ASC) assert len(rows) 2 assert rows[0][name] Li Si # ASCII顺序Li Zhang assert rows[0][salary] 6200.00 # 精度校验6.2 用系统定义参数反向压测把“每天5000条租借”变成sysbench脚本PDF第2页“每天各分公司总共有5000条新的录像出租记录”是压测黄金指标。我用sysbench模拟真实负载# 生成租借数据压测脚本 sysbench oltp_insert \ --db-drivermysql \ --mysql-hostlocalhost \ --mysql-port3306 \ --mysql-usertestuser \ --mysql-passwordpass \ --mysql-dbstayhome \ --tables1 \ --table-size100000 \ --threads50 \ --time300 \ --report-interval10 \ run关键参数依据PDF设定--threads50模拟50并发用户PDF说“每个分公司三名成员同时访问”100分公司≈300并发但租借集中在晚高峰按峰值20%估算50线程合理--time300压测5分钟覆盖“下午6–9点”中任意时段--table-size100000匹配PDF“100000名会员”基线。后悔药第一次压测时发现rental表无索引QPS仅8TPS5。加INDEX(member_id, rent_date)后QPS飙到210TPS180——这印证了PDF里“高峰期响应5秒”的可行性前提是索引到位。6.3 法律合规性验证用GDPR检查清单核对PDF字段PDF第3页“法律管理个人数据”结合GDPR原则我制作字段级检查表PDF字段GDPR要求实现方式验证SQL会员姓名、地址数据最小化视图过滤非必要字段SELECT * FROM member_safe;—— 只返回脱敏地址员工薪水目的限定采购员角色无法SELECT salarySHOW GRANTS FOR procurement%;—— 确认无salary权限注册日期存储期限member表statusarchived且last_rental_date有索引EXPLAIN SELECT * FROM member WHERE statusarchived AND last_rental_date 2022-01-01;—— 确认走索引从那以后我每次拿到需求文档第一件事不是画ER图而是打开PDF用CtrlF搜“唯一”“全局”“每天”“每月”“必须”“禁止”这些词把它们全部标黄然后一条条转成DDL、DML、GRANT和测试用例。这份StayHome文档里藏着的不是过时的录像租赁业务而是一套完整的、经得起推敲的需求工程方法论——它不教你技术但它逼你思考技术背后的业务重量。希望帮到你。本文还有配套的精品资源点击获取