環境說明
- 系統環境: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但想動手試試搭數據庫的朋友提供幫助;
- 完整源碼地址(僅供參考)