兼职网站管理系统数据库设计:DFD到ER图与校验位全解析
简介兼职网站管理系统数据库分析设计文档面向系统分析与数据库设计初学者、计算机相关专业学生及毕业设计者系统梳理了兼职平台从需求分析到数据库落地的完整过程重点解决招聘信息处理复杂、岗位匹配针对性不强、用户信任与数据安全等核心问题。包内为1个doc文档约491KB结构按管理信息系统分析、设计、实施三大部分展开包含项目背景、系统目标、可行性研究、人员分配与工作进度安排、系统逻辑方案以及代码设计、数据库结构设计、输入输出设计、安全保密设计等模块并配有ER图与数据流程图直观展示实体关系与数据流转路径。目前已有434人学习。文档详细到用户表、职位表、申请表等核心表的设计思路可帮助读者掌握用ER图建模、用流程图梳理业务的实践方法也能直接作为课程设计、毕业设计或小型兼职网站系统开发的需求分析与数据库设计参考。1. 别急着建表先让「需求」变成「数据流图」一份兼职网站管理系统的数据库分析设计文档最容易被跳过的恰恰是前三分之一业务流程图、顶层图、分层数据流程图和配套的数据字典。数据库课程设计的常见问题不是表建不出来而是拿到需求直接开写 CREATE TABLE写到外键时才发现「职位申请」和「协议签订」到底谁先谁后都说不清。这份文档真正的价值在于它把复用度极高的建模链路走全了——从数据流程图到 ER 图再到关系模式、9 张核心表和校验位代码设计每一步都留有可对照的中间产物。如果你正在做类似的兼职网站数据库设计或者想把现成的业务库用 sql 转 er 图的方式做逆向梳理前半部分的建模方法比后半部分的表结构更值得抄。2. 从业务流程图到分层 DFD顶层图、一层图怎么画才不丢数据2.1 先画业务流程图把「角色 动作 单据」列全很多设计稿卡在第一张图上原因是角色和单据没对齐。这份兼职网站文档的业务流程实际隐含了四条主线兼职人员和招聘方各自走注册与身份验证招聘方发布职位信息兼职人员申请职位并签订电子协议兼职完成后双方互评产生纠纷时向相关部门提供存根材料。我一般会把每条主线的动作拆成「谁发起、做什么、产出什么单」三列再落成流程图节点。以注册为例求职方兼职人员申请协议填写注册表网站方做身份验证不合格则退回合格则写入用户信息存储招聘方走同样的申请协议、注册、信息验证流程招聘方发布职位信息表网站审核后生成可查询的职位信息双方签订电子协议书网站存根完成后互评评价记录存入反馈信息存储。业务流程图和数据流程图的最直接差异是前者还有「申请协议」「身份验证」这种业务动作后者必须先转化成「数据流 处理 数据存储」三个要素。画完业务流程图再画数据流程图才不会漏掉「不合格注册表」这类反向分支。2.2 顶层图四类外部实体与一条主线数据流程图DFD的顶层图只需要回答一个问题这个系统与外部世界交换哪些数据。兼职网站管理系统里外部实体有四类兼职人员、招聘方、求职方、相关部门。招聘方和求职方可以理解为已注册用户对应登录态兼职人员是未注册或不带身份信息的访客相关部门则是纠纷发生时接收材料的外部机构。顶层图的核心数据流包括职位信息单、简历单、兼职信息、电子协议单、纠纷材料单。它们的主线是「信息单 - 网站审核 - 发布 - 申请 - 协议 - 评价/纠纷」。这里有一个值得注意的设计取舍文档把「兼职人员」和「求职方」画成了两个外部实体。按我的习惯如果是为了讲清楚注册前和注册后两种状态可以在图中保留两个实体但要在数据字典里注明「兼职人员 未注册访客求职方 已注册求职者」如果图面混乱也可以在顶层图合并为一个外部实体到一层图再按状态拆分。2.3 一层图与二层图把「验证、上传、处理、发布」拆给四个加工一层图把顶层图里的单个处理过程细化成多个加工Processing。文档给出了很典型的四个加工P1.1 验证信息、P1.2 上传信息、P1.3 处理信息、P1.4 发布信息并配套了 DB1 到 DB6 的数据存储对应注册表、职位信息、协议单、评价表、简历库等。我之前拆这类系统时通常按「入口校验 - 数据入库 - 业务处理 - 对外发布」四段划分和文档的划分一致。分层图应该逐层对应P1.1 验证信息读入注册表和职位信息输出合格的注册信息和职位信息P1.2 上传信息把简历单、职位信息单写入存储P1.3 处理信息负责电子协议签署、评价反馈、纠纷材料归集P1.4 发布信息面向求职方展示招聘信息、面向招聘方展示简历。分层对照关系如下表图层次外部实体主要处理过程关键数据存储核心数据流顶层图兼职人员、招聘方、求职方、相关部门兼职网站管理系统无存储不跨边界职位信息单、简历单、协议单、纠纷材料单一层图同上P1.0 管理信息DB1 注册表、DB2 职位信息、DB3 简历、DB4 协议、DB5 评价、DB6 纠纷材料合格/不合格注册表、已审核职位信息二层图以上实体 相关部门P1.1 验证、P1.2 上传、P1.3 处理、P1.4 发布DB1-DB6 细化纠纷材料、存档协议单、评价表画完二层图后我习惯做三个自查每条数据流是否都有明确的起点和终点图上的每个数据存储是否能在数据字典里找到对应条目P1.1 在二层图里的输入输出是否和一层图里 P1.0 的输入输出一致。大多数课程设计的扣分点都出在层与层之间数据流编号对不上。3. 数据字典先行23 个数据项与三类核心存储的梳理方法3.1 数据项是一切建模的地基数据字典是连接数据流程图和 ER 图的桥梁。文档里列了 DI01 到 DI23 共 23 个数据项可以分成三组身份账户类包括企业号、应聘者号、用户编号、用户名、用户密码基本属性类包括姓名、年龄、性别、工龄、工资、电话、地址、邮政编码、邮箱、日期业务属性类包括招聘号、招聘职务、员工数量、应聘职务、期望工资、工作城市、学历。下表是几个容易在评审时被追问的项编号数据项名类型与取值使用位置DI01企业号唯一代码整数招聘单位主键、在线申请外键DI02应聘者号唯一代码整数求职者主键、简历外键DI03姓名文本长度 10 字符用户信息、简历信息DI08工龄整数 0..100简历、筛选条件DI14应聘职务枚举按个人意向定义在线申请、简历DI19工作城市文本长度 30 字符职位查询条件DI20期望工资整数简历、职位匹配DI21用户编号整数网站登录号全局用户标识数据项表是 ER 图属性列的来源。我做数据建模时会先核查数据项是否覆盖了数据流程图里出现的每一条数据流DF1 企业信息对应企业号与招聘信息DF2 协议对应企业号、应聘者号、简历号与日期DF3 应聘人信息对应姓名、性别、工龄、期望工资等。数据项缺了后续 ER 图必然缺属性这是可以追根溯源的逻辑链条。3.2 数据流与数据存储条目怎么归并数据字典里还有数据流、数据存储和处理过程三类条目。文档给的数据流 DF1-DF5 覆盖了企业信息、协议、应聘人信息、纠纷信息和评价信息数据存储 DT11-DT114 对应应聘人信息表、招聘人信息表、协议书统计表、职务信息表。实际做课程设计时经常出现的失误是DFD 图上的 DB1-DB6 和数据字典里的 DT 编号各写一套。解决办法是约定「图上标 DB 号字典里写 DT 号并建立对照说明」。例如 DB1 注册表面对应 DT11 应聘人信息表DB2 职位信息对应 DT14 职务信息表DB4 对应 DT12 招聘人信息表。这一步梳理好了后面做 ER 图时实体的边界会非常清晰。3.3 从字典到代码设计与校验需求数据字典还有一层容易被忽略的作用它决定了哪些对象需要全局唯一编码。DI01 企业号、DI02 应聘者号、DI05 招聘号在后续代码设计里都被重新编码而简历号、用户编号这类只需要表内自增的字段则不必设计复杂规则。数据字典里每出现一个「代码唯一」的说明就对应着后面代码设计里的一个编码对象这也是文档第五部分能顺理成章展开算数级数法校验位的原因。4. 兼职网站 ER 图拆解E-R 模型到关系模式的转换与 9 张表设计4.1 实体、属性、联系这份 ER 图里的三类关系E-R 模型的核心是把数据字典里的数据项归类到实体。这份文档的实体有求职人员、招聘单位、网站管理员、相关部门再加一个连接求职人员与招聘单位的核心联系——电子协议书。兼职网站系统的特点在于两个用户体系个人与企业属性差异很大所以求职人员与招聘单位必须拆成两个实体不能做成一张用户表再靠类型字段区分。实体间联系可以归纳为三类求职人员与招聘单位之间是 m:n一个求职者可向多个招聘单位投递一个招聘单位接收多个求职者对应在线申请与协议签订网站管理员与各类信息之间是 1:n一个管理员维护多条职位和简历信息网站管理员与相关部门之间是 m:n一次纠纷可能涉及多个管理员提供材料一个部门也协助处理多起纠纷。ER 图里主键的表示规则是下划线标注用户编号、招聘单位编号、协议编号这些作为主键的属性都要标下划线外键则不需要在概念模型里标注留到逻辑结构设计。4.2 转换规则1:n、m:n 联系落表的标准做法E-R 图转关系模式有固定的三条规则这也是数据库课程设计的必考点联系类型转换规则本系统的落点1:1 联系任选一端实体表加入另一端主键作为外键网站管理员与账号信息1:n 联系在 n 端实体表中加入 1 端主键作为外键管理员管理多条招聘信息、多条简历信息m:n 联系新建独立关系表包含双方主键及联系属性在线申请、协议签订、互评、协助调查文档给出的关系模式与规则完全吻合。注册信息表用户编号用户姓名用户密码电子邮件是用户主表招聘单位表以招聘单位编号为主键并保留招聘信息编号作为外键在线申请是典型的 m:n 派生关系包含提交简历编号、招聘单位编号、求职者编号外加招聘职位和应聘职位两个联系属性协议书则是求职人员与招聘单位之间另一个 m:n 联系的实体化。把 E-R 图转成 9 张关系模式就是按上面这张表机械执行不靠灵感。4.3 核心建表语句SQL Server 2008 风格落地关系模式确认后写建表 SQL 只是体力活。以下是我常用来起步的三张核心表风格按文档给定的 SQL Server 2008 调整CREATE TABLE dbo.ResumeInfo ( GetJobInfoID INT IDENTITY(1,1) PRIMARY KEY, PersonID INT NOT NULL, Name NVARCHAR(10) NOT NULL, Sex NCHAR(1) NOT NULL DEFAULT N男, Email NVARCHAR(50) NULL, Phone VARCHAR(20) NULL, Education NVARCHAR(20) NULL, WorkPosition NVARCHAR(30) NULL, WorkCity NVARCHAR(30) NULL, Wage INT NULL, Experience NVARCHAR(MAX) NULL, SelfIntroduction NVARCHAR(MAX) NULL, PublishTime DATETIME NOT NULL DEFAULT GETDATE(), LookTimes INT NOT NULL DEFAULT 0 ); CREATE TABLE dbo.JobPost ( GiveJobInfoID INT IDENTITY(1,1) PRIMARY KEY, CompanyID INT NOT NULL, CompanyName NVARCHAR(50) NOT NULL, WorkPosition NVARCHAR(30) NOT NULL, WorkCity NVARCHAR(30) NULL, Headcount INT NOT NULL DEFAULT 1, JobDesc NVARCHAR(MAX) NULL, JobRequest NVARCHAR(200) NULL, PublishTime DATETIME NOT NULL DEFAULT GETDATE(), LookTimes INT NOT NULL DEFAULT 0 ); CREATE TABLE dbo.Application ( ResumeID INT IDENTITY(1,1) PRIMARY KEY, PersonID INT NOT NULL, CompanyID INT NOT NULL, GiveJobInfoID INT NOT NULL, PersonName NVARCHAR(10) NOT NULL, CompanyName NVARCHAR(50) NOT NULL, ApplyPosition NVARCHAR(30) NULL, ApplyTime DATETIME NOT NULL DEFAULT GETDATE(), CONSTRAINT FK_Application_Person FOREIGN KEY (PersonID) REFERENCES dbo.ResumeInfo(PersonID), CONSTRAINT FK_Application_Company FOREIGN KEY (CompanyID) REFERENCES dbo.JobPost(CompanyID) );建表逻辑说明GetJobInfoID 和 GiveJobInfoID 用 IDENTITY(1,1) 自增主键与代码设计中的业务编码解耦——自增主键只保证物理唯一业务编号第 5 章讲的 135010012 这类才是跨系统通信时使用的标识PersonID 在 ResumeInfo 里是外键不在此表生成意味着必须先有用户注册信息才能创建简历Headcount 设置 NOT NULL DEFAULT 1避免招聘人数漏填时出现 NULL 影响统计Experience 和 SelfIntroduction 用 NVARCHAR(MAX) 承接不定长文本原始文档里「文本」类型最容易在评审时被追问直接给 MAX 是更稳妥的答案。4.4 课程设计里最容易扣分的字段设计问题对照文档中数据表设计有几个字段标注问题值得修正用户信息表里 Password 的必填字段标注很含糊注册流程必须有密码落地时应为 NOT NULL所有「日期格式」字段建议直接用 DATETIME 并加 DEFAULT GETDATE()不要用 VARCHAR 存日期否则后续排序和范围查询都会出问题性别、工作类型这类有限取值字段用 NCHAR(1) 或 TINYINT 加约束比自由文本更抗脏数据在线申请表里的 PersonName 和 CompanyName 属于冗余字段但对于兼职网站的业务场景冗余快照能避免企业改名或用户注销后历史申请记录无法显示属于值得保留的反范式设计。5. 代码设计与校验位算数级数法模 11如何压低录入错误率5.1 区间码 顺序码把类别和地域写进编码文档里的代码设计采用区间码与顺序码结合的方案第一位用 1 表示求职个人、2 表示招聘单位紧接的几位代表省市区段后面是顺序编号最后一位是校验码。以求职者代码 135010012 为例首位的 1 区分个人与单位3501 段代表省份与城市顺编号 0012 代表该城市内的求职者顺序末位 2 是校验码。招聘信息代码 235010010010018 则层级更多2招聘单位 3501地域 001招聘单位编号 001职位类别 001职位品种 8校验码。这种编码的优点是排序即分类WHERE WorkCode LIKE 23501001% 就能筛出某个区域某家单位的全部职位缺点是码长会随层级增加膨胀在招聘信息这类高频数据里不适合做物理主键更适合做业务展示字段。5.2 校验位的计算过程从左到右赋权模 11 取余文档采用的算数级数法计算校验位过程如下原代码各位从左到右乘以位权 1、2、3…n求乘积之和再对 11 取余余数即为校验码。以求职者原代码 13501001 为例代码位13501001位权12345678乘积161505008乘积之和 161505008 3535 ÷ 11 3 余 2校验码为 2完整代码为 135010012。招聘单位 23501001 的计算同理261505008 3636 mod 11 3完整代码 235010013。有两个细节容易踩坑一是位权的方向必须在代码设计说明书里写死从左到右赋权得到的校验位和从右到左赋权完全不同。二是当模数取 11 时权序列通常会跳过 11文档里招聘信息代码的位权序列为 1、2、3…10、12、13、14、15跳过了 11这是刻意避开与模数同值否则乘积会出现不该出现的整除偏好。这两点在报告评审时讲清楚比表结构更能体现设计者是否真正理解校验码原理。5.3 用脚本批量验证校验码课程设计的代码设计部分经常只停留在纸面演算实际录入时根本没人手工算。我会写一个极简脚本把校验逻辑固化成函数后对接注册接口def calc_check_digit(original_code: str, mod: int 11, skip: int | None 11) - str: # 从左到右赋予 1..n 的算数级数位权可指定跳过与模数同值的权 total 0 weight 1 for ch in str(original_code): if skip is not None and weight skip: weight 1 total int(ch) * weight weight 1 check total % mod # 余数 10 的处理需与报告约定一致常见做法是映射为字符 X 或数字 0 return X if check 10 else str(check) # 验证文档里的两个例子 assert calc_check_digit(13501001) 2 # 完整代码 135010012 assert calc_check_digit(23501001) 3 # 完整代码 235010013 print(calc_check_digit(23501001001001)) # 输出 8对应招聘信息代码 235010010010018函数逻辑说明calc_check_digit 接收原始代码字符串对每一位乘以递增的算术级数位权参数 skip 用于跳过与模数同值的权数 11返回值是模 11 的余数其中余数 10 映射为 X 或 0 需要提前约定。这样注册、录入职位时只需把不带校验位的原始编码传入函数就能得到合规的完整编码避免人工算错。如果想验证整批存量数据把线上的 CompanyID 列取出来循环判断末位是否等于 calc_check_digit(原码)一分钟就能跑完全库主数据。6. 提效与自查从 PowerDesigner 画 ER 图到 SQL Server 落库的稳定性清单6.1 用 sql 转 er 图做逆向检查数据库课程设计和真实项目里PowerDesigner 画 ER 图是最常见的做法但很多人的 ER 图和建表 SQL 是各画各的最终文档里的实体关系与实际库结构对不上。更高效的方式是正向建模与逆向核对并用在 PowerDesigner 里新建 Physical Data Model选择 SQL Server 2008 的 DBMS直接粘贴上一章的 CREATE TABLE 语句生成图表如果已有线上库用 Database - Reverse Engineer Database 连接数据库实例让工具自动生成 ER 图再把生成的图与文档中的 E-R 图对照。重点看三类不一致m:n 联系是否被错误合并成外键直连、主键是否有下划线标注、关系线上是否标注了基数1、n、m。工具只能保证图与库一致不能保证关系建模正确校正基数必须靠人工。6.2 三范式与索引自查清单落库前我建议对每张表过一遍范式检查。第一范式看是否存在重复组简历表里「工作经历」如果是多值字段写成 Experience1、Experience2 这种列就是违反第一范式应该拆成独立的工作经历表。第二范式看是否存在部分依赖在线申请表的主键如果是复合主键PersonID JobInfoID那么 PersonName 只依赖于 PersonID不依赖完整主键这就是部分依赖应该拆出文档把 ResumeID 做成独立主键就规避了这个问题。第三范式看传递依赖简历表里的期望工资 Wage 如果其实来自某个薪酬等级表就不该直接存数字。索引层面的实用建议是外键列PersonID、CompanyID、GiveJobInfoID一律建非聚集索引因为这决定了 JOIN 的性能LookTimes 这样的点击量字段在频繁做 ORDER BY 时建索引否则不用。不要为了「像报告」而对每个列都建索引兼职网站的真实读写比是读多写少索引过多会拖慢职位信息发布这个写入路径。6.3 验收前用一条 SQL 对账数据字典和表验收阶段最直接的技巧是用数据字典反向核对表字段。把文档中的表 4 个人简历信息表的字段清单与 ResumeInfo 的 sys.columns 对比SELECT c.name AS column_name, t.name AS data_type FROM sys.columns c JOIN sys.types t ON c.user_type_id t.user_type_id WHERE c.object_id OBJECT_ID(dbo.ResumeInfo);运行后逐项与文档的字段说明对照能立刻发现遗漏字段和类型偏差再用外键 LEFT JOIN 反查孤儿数据SELECT COUNT(*) FROM dbo.Application a LEFT JOIN dbo.ResumeInfo r ON a.PersonID r.PersonID WHERE r.PersonID IS NULL; 结果大于 0 就说明录入流程绕过了用户注册校验需要回到 P1.1 验证信息的逻辑里排查。我把这份对账 SQL 和上面的三范式清单存成模板每次课程设计或新项目建库都先跑一遍比对着文档抄一遍更能发现问题。本文还有配套的精品资源点击获取