简介:这份资源是《数据库应用》课程期末大作业的完整课程设计报告,面向高校数据库相关专业学生及需要完成企业级数据库课程设计的开发者。报告以企业人事管理系统为案例,完整覆盖从系统需求分析、概念结构设计、逻辑结构设计到物理结构设计、视图设计、数据保护设计及系统实现的全流程,并给出员工表、考勤表、薪资表、用户表等核心表结构及字段约束说明,适合作为课程设计参考模板或数据库设计入门范例。资源包共1个doc文档,压缩包约2.58MB,内容为正式发布的课程设计报告,目录结构清晰,便于按章节查阅。目前已有6645人学习下载,读者可从中获取完整的设计思路、表结构定义、视图与权限设计方法,以及数据加密与备份恢复等安全策略,帮助快速理解数据库设计在实际项目中的落地方式。
1. 从一份课程设计报告说起:企业人事管理系统的数据库到底长什么样
如果你正在做《数据库应用》期末大作业,或者需要一份能直接跑通的 MySQL 课程设计参考,这份《企业人事管理系统》课程设计报告值得拆开看。它不是那种只贴几张 ER 图就交差的文档,而是完整走了一遍需求分析、概念结构、逻辑结构、物理结构、视图设计、数据保护到系统实现的全流程,最终落到四张核心表:Staff、Attendance、Salary、Puser。整套设计围绕一个真实场景展开——企业需要快速掌握人事分布、管理考勤与薪资、同时保证数据安全。适合数据库入门者照着复现,也适合已经会写 SQL 但没做过完整项目的人补齐“从设计到落地”的链路。下面我按实际动手顺序,把这份报告里的关键设计拆成可抄作业的步骤。
2. 四张核心表怎么建:从逻辑结构到物理结构的映射与约束设计
2.1 先理清实体关系,再动手写 CREATE TABLE
这份报告的逻辑结构设计部分给出了四个实体:员工、员工考勤信息、员工薪资、用户。对应到物理结构就是四张表。很多同学一上来就写建表语句,结果字段类型和约束反复改,血泪经验是先把逻辑结构里的属性列清楚,再映射成列名和数据类型。
员工实体的属性包括:员工姓名、工号、性别、身份证号、出生日期、年龄、民族、邮箱、学历、毕业学校、所学专业、入职时间、部门名称、部门编号、职位、司龄。考勤实体包括:员工姓名、工号、日期、通勤、出差、加班。薪资实体包括:工资编号、员工姓名、工号、基本工资、补助、奖金、代扣保险、实发工资。用户实体包括:用户名、用户密码、用户权限、员工姓名、职位。
映射到表时,报告里把 Staff 表的主键设为 IDcard(身份证号),同时 Sno(工号)加了 Unique 约束。Attendance 表用 Sno 作为主键的一部分,Salary 表用 SaNo 作为主键。Puser 表用 uname 作为主键。这里有个细节值得注意:Staff 表里 Sno 是 Unique 但不是主键,IDcard 才是主键。实际建表时如果你想让工号作为主键也可以,但报告的选择是身份证号唯一标识一个人,工号作为业务唯一键。两种做法都行,关键是要在文档里说清楚为什么这么选。
2.2 建表语句与字段类型选择
下面是根据报告中的表结构整理出的建表 SQL。我补上了引擎和字符集设置,这是课程设计里容易被忽略但实际部署时必须写的部分。
-- 员工基本信息表 CREATE TABLE Staff ( Sname CHAR(10) NOT NULL, -- 姓名 Sno CHAR(5) NOT NULL UNIQUE, -- 工号,业务唯一键 Ssex CHAR(1) NOT NULL, -- 性别 IDcard CHAR(18) NOT NULL UNIQUE, -- 身份证号,主键 Birthday DATE NOT NULL, -- 出生日期 Sage SMALLINT NOT NULL, -- 年龄 Snation CHAR(10) NOT NULL, -- 民族 Mail CHAR(40) NOT NULL, -- 邮箱 Education CHAR(10) NOT NULL, -- 学历 School CHAR(20) NOT NULL, -- 毕业学校 Sdept CHAR(20) NOT NULL, -- 所学专业 Etime DATE NOT NULL, -- 入职时间 Dname CHAR(20) NOT NULL, -- 部门名称 Dno CHAR(5) NOT NULL, -- 部门编号 Job CHAR(20) NOT NULL, -- 职位 jage CHAR(10) NOT NULL, -- 司龄 PRIMARY KEY (IDcard) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 考勤信息表 CREATE TABLE Attendance ( Sname CHAR(10) NOT NULL, Sno CHAR(5) NOT NULL, Adate CHAR(10) NOT NULL, -- 月份,报告里用 CHAR(10) Ac SMALLINT NOT NULL, -- 在岗天数 Business SMALLINT NOT NULL, -- 出差天数 Overtime SMALLINT NOT NULL, -- 加班天数 PRIMARY KEY (Sno, Adate) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 薪资信息表 CREATE TABLE Salary ( SaNo CHAR(5) NOT NULL UNIQUE, -- 工资编号 Sname CHAR(10) NOT NULL, Sno CHAR(5) NOT NULL, Bp CHAR(10) NOT NULL, -- 基本工资 Subsiby CHAR(10) NOT NULL, -- 补助 bonus CHAR(10) NOT NULL, -- 奖金 Insurance CHAR(10) NOT NULL, -- 代扣保险 pay CHAR(10) NOT NULL, -- 实发工资 PRIMARY KEY (SaNo) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 系统用户表 CREATE TABLE Puser ( uname CHAR(5) NOT NULL, Upassword CHAR(6) NOT NULL, Authority CHAR(10) NOT NULL, Sname CHAR(10) NOT NULL, Job CHAR(20) NOT NULL, PRIMARY KEY (uname) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;逻辑说明:Staff 表用 IDcard 做主键,Sno 加 UNIQUE,这样一个人只能有一条员工记录,工号也不会重复。Attendance 表用 Sno 和 Adate 做联合主键,保证同一个员工同一个月只有一条考勤记录。Salary 表用 SaNo 做主键,Sno 作为外键关联员工。Puser 表独立管理登录账号。
参数说明:CHAR 类型在 MySQL 里是定长,报告里大量使用 CHAR(10)、CHAR(5),实际如果字段长度变化大,用 VARCHAR 更省空间。但课程设计里用 CHAR 没问题,老师一般看的是约束和关系设计。SMALLINT 用于天数、年龄这类小整数足够。日期字段用 DATE,考勤月份用 CHAR(10) 是报告里的选择,实际可以用 DATE 或 VARCHAR(7) 存“2022-06”这种格式。
提示:建表时把 ENGINE 设为 InnoDB,否则外键约束不生效。字符集用 utf8mb4,避免中文乱码。
2.3 约束条件的取舍与常见误用
报告里每个表都设了 NOT NULL,主键和 Unique 也标了。但有一个点值得展开:Staff 表里 Sno 是 Unique,IDcard 是主键,这意味着工号和身份证号都不能重复。实际业务里工号可能离职后回收再分配,这时候 Unique 就会冲突。课程设计阶段不用考虑这么细,但如果你想让设计更严谨,可以在文档里加一句“工号离职后保留历史记录,不回收”。
另一个容易翻车的地方是 Attendance 表的主键设计。报告里写的是 Sno 是 Unique 和 primary key,但考勤是按月记录的,同一个员工多个月份应该有多条记录。如果 Sno 单独做主键,那就只能存一条考勤。正确的做法是 Sno + Adate 联合主键,我上面的建表语句已经按这个逻辑调整了。这是原报告里一个明显的坑,复现的时候要注意。
3. 视图与权限:让不同角色看到不同数据的具体做法
3.1 视图设计:把敏感字段挡在视图外面
报告里对视图的描述比较概括,核心思想是:不同职位的人看同一张表,应该看到不同的列。比如普通员工查薪资,只能看到自己的实发工资,看不到别人的基本工资和奖金;人事部可以看到全部。实现方式就是建视图,把敏感列过滤掉,然后给不同用户授予不同视图的 SELECT 权限。
下面是根据报告思路整理的几个视图示例:
-- 视图1:员工公开信息视图,隐藏身份证号和薪资相关 CREATE VIEW v_staff_public AS SELECT Sname, Sno, Ssex, Dname, Job, Etime FROM Staff; -- 视图2:人事部专用视图,包含完整信息 CREATE VIEW v_staff_hr AS SELECT * FROM Staff; -- 视图3:个人薪资视图,只显示实发工资 CREATE VIEW v_salary_self AS SELECT Sname, Sno, pay FROM Salary; -- 视图4:考勤汇总视图,按员工统计加班和出差 CREATE VIEW v_attendance_summary AS SELECT Sno, Sname, SUM(Ac) AS total_work_days, SUM(Business) AS total_business_days, SUM(Overtime) AS total_overtime_days FROM Attendance GROUP BY Sno, Sname;逻辑说明:v_staff_public 把身份证号、邮箱、学历等敏感信息排除,适合普通员工查询通讯录。v_staff_hr 保留全字段,只授权给人事角色。v_salary_self 只暴露实发工资,员工只能看自己的那一行——这里还需要配合 WHERE 条件或应用层过滤,视图本身不限制行。v_attendance_summary 用 GROUP BY 做聚合,方便月度统计。
参数说明:视图不存储数据,每次查询都从基表取。如果基表数据量大,视图查询会慢,可以考虑物化视图,但 MySQL 不支持原生物化视图,需要用定时任务或触发器维护汇总表。
3.2 用户密码加密与角色权限分配
报告里提到密码加密用 MD5(),插入时对密码做哈希。具体做法是在 INSERT 语句里调用 MD5 函数:
-- 插入用户时对密码做 MD5 加密 INSERT INTO Puser (uname, Upassword, Authority, Sname, Job) VALUES ('zhangsan', MD5('123456'), 'admin', '张三', '人事经理'); -- 登录验证时比对哈希值 SELECT * FROM Puser WHERE uname = 'zhangsan' AND Upassword = MD5('123456');逻辑说明:MD5 是单向哈希,数据库里存的是密文,即使被看到也无法直接还原明文。登录时把用户输入的密码做同样的 MD5 运算,比对结果。
参数说明:MD5 现在安全性不够高,实际项目建议用 SHA2 或 bcrypt。但课程设计里用 MD5 足够,老师一般不会深究。注意 CHAR(6) 存 MD5 结果是不够的,MD5 输出是 32 位十六进制字符串,所以 Upassword 字段至少要 CHAR(32)。原报告里写 CHAR(6) 是个明显的设计缺陷,复现时改成 CHAR(32) 或 VARCHAR(64)。
角色权限方面,报告里定义了角色 A,可以访问 Staff、Attendance、Salary、Puser 四张表,拥有 delete、update、select、insert 权限。实际 MySQL 里的授权语句:
-- 创建角色 CREATE ROLE 'role_hr'; -- 授予权限 GRANT SELECT, INSERT, UPDATE, DELETE ON company_db.Staff TO 'role_hr'; GRANT SELECT, INSERT, UPDATE, DELETE ON company_db.Attendance TO 'role_hr'; GRANT SELECT, INSERT, UPDATE, DELETE ON company_db.Salary TO 'role_hr'; GRANT SELECT ON company_db.Puser TO 'role_hr'; -- 创建用户并分配角色 CREATE USER 'hr_user'@'localhost' IDENTIFIED BY 'password123'; GRANT 'role_hr' TO 'hr_user'@'localhost'; SET DEFAULT ROLE 'role_hr' TO 'hr_user'@'localhost';逻辑说明:先建角色,把权限授予角色,再把角色分配给具体用户。这样以后调整权限只需要改角色,不用逐个用户改。
参数说明:MySQL 8.0 才支持 CREATE ROLE,5.7 需要直接给用户授权。如果用的是 5.7,把 GRANT 语句里的角色名换成用户名即可。Puser 表只给了 SELECT 权限,因为用户管理一般由 DBA 在后台做,应用层不需要改这个表。
注意:授权时库名和表名要写对,company_db 换成你实际的数据库名。localhost 表示只允许本机连接,如果要远程访问改成 %。
4. 避坑与排查:建表和授权时最容易翻车的五个地方
4.1 现象:建表时报 “Specified key was too long”
原因:CHAR(18) 的 IDcard 加上 utf8mb4 字符集,索引长度可能超过 InnoDB 的限制。utf8mb4 每个字符占 4 字节,CHAR(18) 就是 72 字节,加上其他索引列可能超限。
解决:把 IDcard 改成 VARCHAR(18) 或者用 utf8 字符集。如果必须用 utf8mb4,可以设置前缀索引:PRIMARY KEY (IDcard(10)),但这样会失去唯一性保证。更好的做法是身份证号用 CHAR(18) 但字符集设为 ascii,因为身份证号只含数字和字母 X。
4.2 现象:插入中文报 “Incorrect string value”
原因:数据库或表的字符集不是 utf8mb4,或者连接字符集不对。
解决:建库时指定CREATE DATABASE company_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;,建表时也指定。连接时在 JDBC URL 或客户端设置里加characterEncoding=utf8。如果已经建好表,用ALTER TABLE Staff CONVERT TO CHARACTER SET utf8mb4;转换。
4.3 现象:MD5 加密后密码存不进去,提示 “Data too long”
原因:原报告里 Upassword 字段是 CHAR(6),但 MD5 输出 32 位字符串,长度不够。
解决:把 Upassword 改成 CHAR(32) 或 VARCHAR(64)。如果已经建表,用ALTER TABLE Puser MODIFY Upassword CHAR(32) NOT NULL;。这是原报告里最明显的字段长度错误,复现时一定要改。
4.4 现象:授权后用户还是连不上数据库
原因:MySQL 用户是user@host的形式,'hr_user'@'localhost'和'hr_user'@'%'是两个不同的用户。如果应用从另一台机器连接,localhost 用户不生效。
解决:确认连接来源,创建对应的 host 用户。CREATE USER 'hr_user'@'%' IDENTIFIED BY 'password123';然后重新授权。另外检查防火墙和 MySQL 的 bind-address 配置。
4.5 现象:视图查询报 “View's SELECT contains a subquery in the FROM clause”
原因:MySQL 5.7 之前不支持在视图的 FROM 子句里用子查询,8.0 支持但有些版本仍有兼容问题。
解决:把子查询改成 JOIN 或者拆成两个视图。比如CREATE VIEW v AS SELECT * FROM (SELECT ...) AS t;在旧版本会报错,改成CREATE VIEW v AS SELECT ... FROM table1 JOIN table2 ...。
5. 从建表到查询:用 Python 把系统跑起来的一个最小闭环
报告最后一章提到用 Python 实现了数据查看功能。这里给一个最小可运行的 Python 脚本,用 pymysql 连接 MySQL,实现员工信息的查询和视图调用。这个脚本可以直接作为课程设计的“系统实现”部分截图来源。
import pymysql # 连接配置 conn = pymysql.connect( host='localhost', user='hr_user', password='password123', database='company_db', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor ) def query_staff(): """查询员工公开信息视图""" with conn.cursor() as cursor: sql = "SELECT * FROM v_staff_public" cursor.execute(sql) results = cursor.fetchall() for row in results: print(f"姓名: {row['Sname']}, 工号: {row['Sno']}, 部门: {row['Dname']}, 职位: {row['Job']}") def query_salary(sno): """查询指定工号的薪资""" with conn.cursor() as cursor: sql = "SELECT Sname, pay FROM v_salary_self WHERE Sno = %s" cursor.execute(sql, (sno,)) result = cursor.fetchone() if result: print(f"{result['Sname']} 的实发工资: {result['pay']}") else: print("未找到该员工薪资记录") def add_attendance(sno, sname, adate, ac, business, overtime): """插入考勤记录""" with conn.cursor() as cursor: sql = """INSERT INTO Attendance (Sno, Sname, Adate, Ac, Business, Overtime) VALUES (%s, %s, %s, %s, %s, %s)""" cursor.execute(sql, (sno, sname, adate, ac, business, overtime)) conn.commit() print("考勤记录插入成功") if __name__ == '__main__': query_staff() query_salary('10001') add_attendance('10001', '张三', '2022-06', 22, 2, 5)逻辑说明:pymysql 是 Python 连接 MySQL 的常用库,DictCursor 让查询结果以字典返回,方便按列名取值。query_staff 调用视图,query_salary 带参数查询防止 SQL 注入,add_attendance 演示插入并提交事务。
参数说明:host、user、password、database 换成你自己的环境。charset 必须和数据库一致。%s是 pymysql 的占位符,不要用字符串拼接,否则有注入风险。commit() 必须调用,否则插入不生效。
验证方法:先跑 query_staff,应该输出员工列表。再跑 query_salary,传入一个存在的工号,看是否返回实发工资。最后跑 add_attendance,然后去 MySQL 里SELECT * FROM Attendance WHERE Sno='10001';确认数据写入。如果报连接错误,检查用户权限和 host 配置;如果报字符集错误,检查 charset 参数。
从那以后我每次做课程设计,都会先把建表语句在 MySQL 里跑一遍,确认没有字段长度和字符集问题,再写应用层代码。这样能省掉大量调试时间。希望帮到你。
本文还有配套的精品资源,点击获取