环境说明
- 系统环境:Windows 10 专业版
- 数据库管理系统:MySQL
- 设计工具:Navicat for MySQL
- 编程工具:Qt 5.12.3 / VS
流程图
- 建立数据库
- 建立数据表
数据字典
- 学生表
- 体检表
- 成绩表
- 课程表
- 用户表
ER图
- 学生ER图
- 体检ER图
- 成绩ER图
- 课程ER图
- 用户ER图
- 总体ER图
关系模式及规范化
关系模式定义
设计学生信息管理数据库,包括学生信息、体检信息、课程信息、成绩信息、用户信息五个关系,其关系模式中每个实体定义的属性如下:
- 学生信息:(学号,姓名,性别,年龄,身份证号,联系电话,入学时间,毕业时间,学业情况,备注);
- 体检信息:(学号,身高,体重,辨色,左眼视力,右眼视力,左耳听力,右耳听力,腿长比,血压,病史,备注);
- 课程信息:(课程号,课程名,备注);
- 成绩信息:(学号,课程号,上次考试时间,考试次数,分数);
- 用户信息:(用户名,密码,身份证号);
规范化(3NF)
- 秉持最优化、最简洁的设计原则,应选择合理的范式规范;
- 在最开始的设计中,我引入了地址、院系、年级、类似“XX1901”的班级命名制度;
- 由于师生信息本身的复杂性,全部消除非主键的部分依赖和传递依赖,需要新增和删改很多表来避免数据冗余,具体操作如下:
- 根据日期的可分性,可分出国家表、地区表等(1NF);
- 根据年级对班级的部份依赖,将年级更改为入学年份或届数(2NF);
- 根据班级对院系、专业的部份依赖, 学生表中分出院系表、班级表、专业表(2NF);
- 根据班级对年级、院系、专业复杂的传递依赖,亦可将几类键分出(3NF)。
开发流程
Qt设计界面
Navicat搭建库
部分后端代码
#include "mysql.h"
#include "mainwindow.h"
#include <QDebug>
My_Sql::My_Sql()
{
}
void My_Sql::initsql()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setUserName("root");
db.setPassword("123456");
db.setDatabaseName("student");
if(db.open())
{
qDebug() << "database is established!";
createtable();
return;
}
else
{
qDebug() << "build error!";
return;
}
}
// 创建数据库操作
void My_Sql::createtable()
{
query = new QSqlQuery;
//建表
query->exec("create table user(name VARCHAR(30) UNIQUE NOT NULL, passward VARCHAR(30), identify VARCHAR(30) PRIMARY KEY)");
query->exec("create table studentInfo(stuaccount VARCHAR(30) PRIMARY KEY UNIQUE NOT NULL, stuname VARCHAR(30), stusex ENUM('Male', 'Female') NOT NULL, stuage INT, identify VARCHAR(30) UNIQUE NOT NULL, tel VARCHAR(20), enroll_time DATE, leave_time DATE, scondition enum('Studying', 'Educated', 'Off'), stu_text TEXT)");
query->exec("create table healthInfo(stuaccount VARCHAR(30) PRIMARY KEY UNIQUE NOT NULL, stuname VARCHAR(30) NOT NULL, height FLOAT, weight FLOAT, differentiate ENUM('Normal', 'Weak', 'Blind'), left_sight FLOAT, right_sight FLOAT, left_ear ENUM('Normal','Weak'), right_ear ENUM('Normal','Weak'), legs ENUM('Normal','Diff'), pressure ENUM('Normal','High','Low'), history VARCHAR(50), h_text TEXT)");
query->exec("create table courseInfo(classid INT PRIMARY KEY UNIQUE NOT NULL AUTO_INCREMENT, classname VARCHAR(30), class_text TEXT)");
query->exec("create table gradeInfo(stuaccount VARCHAR(30) PRIMARY KEY UNIQUE NOT NULL, classid INT NOT NULL, lasttime date, times INT default 1, grade float default 0, constraint grade_acc_fk FOREIGN KEY(stuaccount) REFERENCES studentInfo(stuaccount), constraint grade_cid_fk FOREIGN KEY(classid) REFERENCES courseInfo(classid))");
//添加管理员
query->exec("insert into user value('root', '123456', 'root')");
//索引
query->exec("create index int_name ON studentInfo(stuname)");
query->exec("alter table studentInfo ADD INDEX ind_con(scondition)");
query->exec("create index ind_hname ON healthInfo(stuname)");
//视图
query->exec("create VIEW grade_view AS SELECT g.stuaccount, s.stuname, c.classname, g.lasttime, g.times, g.grade FROM studentinfo s, courseinfo c, gradeinfo g WHERE g.stuaccount = s.stuaccount AND g.classid = c.classid");
//三种触发器
query->exec("CREATE TRIGGER license_stu AFTER INSERT ON licenseInfo FOR EACH ROW BEGIN UPDATE studentInfo SET leave_time=NEW.recv_time, scondition = 'Educated' WHERE stuaccount = NEW.stuaccount; END");
query->exec("CREATE TRIGGER update_name AFTER UPDATE ON studentinfo FOR EACH ROW BEGIN UPDATE healthinfo SET stuname = NEW.stuname WHERE stuaccount = NEW.stuaccount;END");
query->exec("CREATE TRIGGER delete_stu AFTER DELETE ON studentinfo FOR EACH ROW BEGIN DELETE FROM gradeinfo WHERE stuaccount = OLD.stuaccount; DELETE FROM healthinfo WHERE stuaccount = OLD.stuaccount; DELETE FROM licenseinfo WHERE stuaccount = OLD.stuaccount;END");
}
bool My_Sql::inituser(QString name, QString identify, QString passward)
{
query = new QSqlQuery;
QString str = QString("insert into user value('%1', '%2', '%3')").arg(name).arg(identify).arg(passward);
bool ret = query->exec(str);
return ret;
}
bool My_Sql::loguser(QString name, QString passward)
{
query = new QSqlQuery;
QString str = QString("select * from user where name = '%1' and passward = '%2'").arg(name).arg(passward);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
MainWindow* MW = MainWindow::getIntence();
MW->passward = query->value(1).toString();
return true;
}
bool My_Sql::addstu(stuInfo *stu)
{
query = new QSqlQuery;
QString str = QString("insert into studentInfo value('%1', '%2', '%3', %4, '%5', '%6', '%7', '%8', '%9', '%10')")
.arg(stu->account).arg(stu->name).arg(stu->sex).arg(stu->age).arg(stu->identify).arg(stu->tel).arg(stu->enroll_time)
.arg(stu->leave_time).arg(stu->scondition).arg(stu->text);
bool ret = query->exec(str);
return ret;
}
bool My_Sql::deletestu(QString account)
{
query = new QSqlQuery;
QString str = QString("select * from studentInfo where stuaccount = '%1'").arg(account);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("delete from studentInfo where stuaccount = '%1'").arg(account);
query->exec(str);
return true;
}
bool My_Sql::updatestu(my_stu *stu)
{
query = new QSqlQuery;
QString str = QString("select * from studentInfo where stuaccount = '%1'").arg(stu->account);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("update studentInfo set stuname = '%1', stusex = '%2', stuage = %3, identify = '%4', tel = '%5', enroll_time = '%6', leave_time = '%7', scondition = '%8', stu_text = '%9' where stuaccount = '%10'")
.arg(stu->name).arg(stu->sex).arg(stu->age).arg(stu->identify).arg(stu->tel).arg(stu->enroll_time).arg(stu->leave_time).arg(stu->scondition).arg(stu->text).arg(stu->account);
qDebug()<<str;
bool ret = query->exec(str);
return ret;
}
bool My_Sql::addheal(my_heal *heal)
{
query = new QSqlQuery;
QString str = QString("insert into healthInfo value('%1', '%2', '%3', %4, '%5', '%6', '%7', '%8', '%9', '%10', '%11', '%12', '%13')")
.arg(heal->stuaccount).arg(heal->stuname).arg(heal->height).arg(heal->weight).arg(heal->differentiate).arg(heal->left_sight).arg(heal->right_sight)
.arg(heal->left_ear).arg(heal->right_ear).arg(heal->legs).arg(heal->pressure).arg(heal->history).arg(heal->h_text);
bool ret = query->exec(str);
return ret;
}
bool My_Sql::updateheal(my_heal *heal)
{
query = new QSqlQuery;
QString str = QString("select * from healthInfo where stuaccount = '%1'").arg(heal->stuaccount);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("update healthInfo set stuname = '%1', height = '%2', weight = '%3', differentiate = '%4', left_sight = '%5', right_sight = '%6', left_ear = '%7', right_ear = '%8', legs = '%9', pressure = '%10', history = '%11', h_text = '%12' where stuaccount = '%13'")
.arg(heal->stuname).arg(heal->height).arg(heal->weight).arg(heal->differentiate).arg(heal->left_sight).arg(heal->right_sight)
.arg(heal->left_ear).arg(heal->right_ear).arg(heal->legs).arg(heal->pressure).arg(heal->history).arg(heal->h_text).arg(heal->stuaccount);
qDebug()<<str;
bool ret = query->exec(str);
qDebug()<<ret;
return ret;
}
bool My_Sql::deleteheal(QString account)
{
query = new QSqlQuery;
QString str = QString("select * from healthInfo where stuaccount = '%1'").arg(account);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("delete from healthInfo where stuaccount = '%1'").arg(account);
query->exec(str);
return true;
}
bool My_Sql::addgrade(my_grade *grad)
{
query = new QSqlQuery;
QString str = QString("insert into gradeInfo value('%1', %2, %3, %4, %5)")
.arg(grad->stuaccount).arg(grad->classid).arg(grad->lasttime).arg(grad->times).arg(grad->grade);
qDebug()<<str;
bool ret = query->exec(str);
return ret;
}
bool My_Sql::updategrade(my_grade *grad)
{
query = new QSqlQuery;
QString str = QString("select * from gradeInfo where stuaccount = '%1'").arg(grad->stuaccount);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("update gradeInfo set classid = '%1', lasttime = %2, times = %3, grade = %4 where stuaccount = '%5'")
.arg(grad->classid).arg(grad->lasttime).arg(grad->times).arg(grad->grade).arg(grad->stuaccount);
qDebug()<<str;
bool ret = query->exec(str);
return ret;
}
bool My_Sql::deletegrade(QString account)
{
query = new QSqlQuery;
QString str = QString("select * from gradeInfo where stuaccount = '%1'").arg(account);
query->exec(str);
query->last();
int record = query->at() + 1;
if(record == 0)
{
return false;
}
str = QString("delete from gradeInfo where stuaccount = '%1'").arg(account);
query->exec(str);
return true;
}
数据保护
防止用户直接操作数据库
- 用户在登录时需要输入用户名和密码,才能进行操作;
- 若用户忘记密码,可通过登录页面验证身份证号重置密码;
- 一般用户(学生)只可修改密码,仅管理员才能进行用户的增删查改操作;
- 一般用户用户只能用账号登录,通过应用软件访问数据,而没有其他途径可以操作数据库。
用户帐号密码的加密
- 对用户账号的密码进行加密处理,确保任何地方都不会出现明文;
- 可增加密码难易度检测提醒。
角色与权限
数据优化
系统截图
项目总结
- 本项目舍弃了传统的Web开发,剑走偏锋,改用Qt接口尝试,实际上存在一定的局限性;在数据库方面,目前仅实现了基本的增删查改功能,UI方面也尚未优化;
- 数据库的前期设计工作较为繁琐,但熟练了之后还是能较快的上手;
- 作为数据库课设中最简单的项目,搭建一个XX信息管理系统对于刚入门的同学来说练手再好不过,希望本文能给一些不会Java但想动手试试搭数据库的朋友提供帮助;
- 完整源码地址(仅供参考)