学生管理系统
一、 系统综述:
本系统是一个简单的学生管理系统,和以前做的一个学生管理系统从功能山来讲,其实是一样的。不同的是,以前的学生管理系统底层的存储部分采用的是文件系统,即使用文件来存储学生记录。对学生记录的增删查改操作也是通过C语言的相关文件操作来实现的。而这里的系统是通过mysql数据库来实现的,即底层的存储是通过Mysql数据库来实现的,对学生记录的增删查改是通过Mysql提供的C语言API实现的,即向Mysql服务器发起SQL语句执行申请,服务器执行完毕之后将结果返回来。
二、 系统结构:
系统结构简要介绍:
1. 界面部分:这里的界面部分并不是真正的图形界面,而是黑窗口里显示的菜单之类。主要包括打印菜单、接收用户输入相关数据之类。其函数包括在meau.c源文件中。
2. 中间层操作函数:这是整个系统的中间层,因为其向上接收用户从界面中选择的模块,向下调用具体的mysql执行语句。
3. Mysql底层操作函数:这是整个系统的底层部分,通过执行sql语句对数据库执行对应的操作,并接受数据库返回的数据。
系统流程介绍:
1. 将用户选择相关功能模块传至中间层。
2. 中间层接收用户的选择,执行相关的操作,并根据要求组合成相关的sql语句,请求mysql服务器执行。
3. Mysql服务器执行后将数据返回给中间层(这里不考虑数据在返回到Mysql底层操作函数的过程),中间层经过解析、输出。
4. 将最终的结果返回给界面。
循环执行以上四步,直到退出系统。
三、代码部分:
/*
名称:具体操作Mysql数据库的相关函数
说明:在这个文件中是一些具体的通过Mysql提供的API进行数据库操作的一些函数。
其中包括:连接数据库、增删查改等操作,是作为底层的Mysql驱动函数。
*/
#include "main.h"
static MYSQL mysql, *sock; //声明MySQL的句柄
//连接数据库:成功返回0,失败返回-1
int ConnectMysql()
{
const char * host = "118.89.148.55"; //主机IP,这里使用的是本人的云主机
// const char * host = "127.0.0.1"; //因为是作为本机测试,所以填写的是本地IP
const char * user = "pan"; //这里改为你的用户名,即连接MySQL的用户名
const char * passwd = "123456"; //这里改为你的用户密码
const char * db = "StuSys"; //这里改为你要连接的数据库的名字
unsigned int port = 3306; //这是MySQL的服务器的端口,如果你没有修改过的话就是3306。
const char * unix_socket = NULL; //unix_socket这是unix下的,我在windows下,所以就把它设置为NULL
unsigned long client_flag = 0; //这个参数一般为0
mysql_init(&mysql); //连接之前必须使用这个函数来初始化
printf("正在连接Mysql数据库...\n");
if ( (sock = mysql_real_connect(&mysql, host, user, passwd, db, port, unix_socket, client_flag) ) == NULL ) //连接MySQL
{
printf("连接失败,原因是: \n");
fprintf(stderr, " %s\n", mysql_ERROR(&mysql));
return -1; //返回失败
}
else
return 0; //返回成功
}
//检查学号是否已经存在
int IfStuNumExist(int stu_num)
{
char query[100];
int temp_num = 0;
MYSQL_RES * result = NULL; //保存结果集
MYSQL_ROW row; //代表的是结果集中的一行
sprintf(query,"%s %d","select count(*) from students where id = ",stu_num);
//查询成功
if(QueryByMysql(query,&result) == 0)
{
if((row = mysql_fetch_row(result)) != NULL ) //读取结果集中的数据,返回的是下一行。因为保存结果集时,当前的游标在第一行【之前】
{
temp_num = atoi(row[0]); //返回的人数
if(temp_num == 0) //学号不存在
return -1;
else
return 0; //学号存在
}
//释放结果集
mysql_free_result(result);
}
else
{
fprintf(stderr, "fail to check student num!\n");
return -1;
}
}
/*查询语句并返回结果集
注意这里的result使用了双重指针为的是在能够给调用此函数的上层函数返回查询的结果集*/
int QueryByMysql(char * query,MYSQL_RES ** result)
{
if(mysql_query(&mysql, query) == 0) //执行查询
{
if ((*result = mysql_store_result(&mysql)) == NULL ) //保存查询的结果
{
fprintf(stderr, "fail to store result!\n");
return -1;
}
else
return 0;
}
else
{
fprintf(stderr, "fail to query table!\n");
return -1;
}
}
//添加一条记录
int AddRecordUseMysql(Student stus)
{
char query[100];
long affect_row = -1;
//组成一条插入SQL语句
sprintf(query,"%s%d,'%s',%d,'%c',%d,%d )","insert into students values( ",stus.stu_num,
stus.name,stus.age,stus.sex,stus.grade,stus._class);
if(mysql_query(&mysql, query) == 0) //执行查询
{
affect_row = mysql_affected_rows(&mysql);
if(affect_row > 0)
return 0;
else
{
printf("Mysql执行插入学生记录失败!\n");
return -1;
}
}
else
{
fprintf(stderr,"Mysql插入学生记录失败!\n");
return -1;
}
}
//在数据库中删除指定学号的记录
int DeleteRecordUseMysql(int stu_num)
{
char query[100];
long affect_row = -1;
//组成一条删除SQL语句
sprintf(query,"%s %d","delete from students where id = ",stu_num);
if(mysql_query(&mysql, query) == 0) //执行查询
{
affect_row = mysql_affected_rows(&mysql);
if(affect_row > 0)
return 0;
else
{
printf("Mysql执行删除学生记录失败!\n");
return -1;
}
}
else
{
fprintf(stderr,"Mysql删除学生记录失败!\n");
return -1;
}
}
//数据库删除所有记录
int DeleteAllRecordUseMysql()
{
char query[100];
long affect_row = -1;
//组成一条删除SQL语句
sprintf(query,"%s","delete from students ");
if(mysql_query(&mysql, query) == 0) //执行查询
{
affect_row = mysql_affected_rows(&mysql);
if(affect_row > 0)
return 0;
else
{
printf("Mysql执行删除所有学生记录失败!\n");
return -1;
}
}
else
{
fprintf(stderr,"Mysql执行删除所有学生记录失败!\n");
return -1;
}
}
//在数据库中查询一条记录
int SearchOneRecordUseMysql(int stu_num,Student * ret_stu)
{
char query[100];
long affect_row = -1;
MYSQL_RES * result = NULL; //保存结果集
MYSQL_ROW row; //代表的是结果集中的一行
//组成一条查询SQL语句
sprintf(query,"%s %d","select * from students where id = ",stu_num);
if(QueryByMysql(query,&result) == 0) //执行查询
{
if((row = mysql_fetch_row(result)) != NULL ) //读取结果集中的数据,返回的是下一行。因为保存结果集时,当前的游标在第一行【之前】
{
//将结果集中的数据提取出来
ret_stu->stu_num = stu_num;
sprintf(ret_stu->name,"%s",row[1]);
ret_stu->age = atoi(row[2]);
sprintf(&(ret_stu->sex),"%s",row[3]);
ret_stu->grade = atoi(row[4]);
ret_stu->_class = atoi(row[5]);
}
else
{
printf("查询结果集为空,查询失败!\n");
return -1;
}
//释放结果集
mysql_free_result(result);
return 0;
}
else
{
fprintf(stderr,"Mysql查询学生记录失败!\n");
return -1;
}
}
//数据库查询所有学生记录信息
int ShowAllRecordsUseMysql(Student *ret_stu,int *num)
{
char query[100];
long affect_row = -1;
MYSQL_RES * result = NULL; //保存结果集
MYSQL_ROW row; //代表的是结果集中的一行
//组成一条查询SQL语句
sprintf(query,"%s","select * from students ");
if(QueryByMysql(query,&result) == 0) //执行查询
{
while((row = mysql_fetch_row(result)) != NULL ) //读取结果集中的数据,返回的是下一行。因为保存结果集时,当前的游标在第一行【之前】
{
//从返回的结果集提取制定数据
(ret_stu[*num]).stu_num = atoi(row[0]);
sprintf((ret_stu[*num]).name,"%s",row[1]);
(ret_stu[*num]).age = atoi(row[2]);
sprintf(&(ret_stu[*num].sex),"%s",row[3]);
(ret_stu[*num]).grade = atoi(row[4]);
(ret_stu[*num])._class = atoi(row[5]);
(*num)++; //学生人数增加
if((*num) > MAX_STUDENT)
{
printf("返回的人数超限!\n");
return -1;
}
}
//释放结果集
mysql_free_result(result);
return 0;
}
else
{
fprintf(stderr,"Mysql查询学生记录失败!\n");
return -1;
}
}
//数据库更新修改一条学生记录
int ModifyRecordUseMysql(Student * mod_stu)
{
char query[100];
long affect_row = -1;
//组成一条更新修改SQL语句
sprintf(query,"%s '%s' %s %d %s '%c' %s %d %s %d %s %d","update students set name =",mod_stu->name, ",age = ",mod_stu->age,
",sex = " ,mod_stu->sex,",grade = ",mod_stu->grade,",class = ",mod_stu->_class,
"where id = ",mod_stu->stu_num);
if(mysql_query(&mysql, query) == 0) //执行查询
{
affect_row = mysql_affected_rows(&mysql);
//如果执行过sql语句后,返回影响的行的数目大于0
if(affect_row > 0)
return 0;
else
{
printf("Mysql执行更新学生记录失败!\n");
return -1;
}
}
else
{
fprintf(stderr,"Mysql更新学生记录失败!\n");
return -1;
}
}
//数据库中查询当前记录数及学生编号
int ShowCurStuNumsUseMysql(int *ret_id,int *num)
{
char query[100];
long affect_row = -1;
MYSQL_RES * result = NULL; //保存结果集
MYSQL_ROW row; //代表的是结果集中的一行
//组成一条查询SQL语句
sprintf(query,"%s","select id from students ");
if(QueryByMysql(query,&result) == 0) //执行查询
{
while((row = mysql_fetch_row(result)) != NULL ) //读取结果集中的数据,返回的是下一行。因为保存结果集时,当前的游标在第一行【之前】
{
ret_id[*num] = atoi(row[0]);
(*num)++; //学生人数增加
}
//释放结果集
mysql_free_result(result);
return 0;
}
else
{
fprintf(stderr,"Mysql查询所有学生id失败!\n");
return -1;
}
}
//退出系统
void Exit(int *flag)
{
*flag = 1;
mysql_close(&mysql); //关闭mysql连接
printf("退出系统,再见了哦!\n");
}
/*
名称:中间层操作函数
说明:这个文件里是一些中间层操作函数,向上接收界面传入的参数(用户的
选择)、向下调用mysql接口函数,执行Mysql语句并返回结果。
其中包括:添加一条学生记录、删除一条学生记录等等。
*/
#include<stdio.h>
#include<conio.h> //为了使用getch()函数
#include "main.h"
//添加一条学生记录
int AddRecord()
{
char temp_str[100];
Student add_stu;
int val = 0;
char c = 0;
//学生编号
while(1)
{
printf("请输入新增加的学生编号(0-10000):");
val = InputtypeofInt();
//scanf("%d",&val);
if(IfStuNumExist(val) == 0) //判断学号是已经存在
printf("学号已经存在了哦,换个学号吧!\n");
else
break;
}
add_stu.stu_num = val;
//姓名
printf("请输入新增加的学生姓名(20个字符):");
scanf("%s",&add_stu.name);
//年龄
while(1)
{
printf("请输入新增加学生的年龄(5-40):");
val = InputtypeOfInt();
// scanf("%d",&val);
if(val>=5 && val <= 40)
break;
else
printf("学生的年龄应该在5-40岁之间哦!\n");
}
add_stu.age = val;
//性别
while(1)
{
printf("请输入新增加的学生性别(M\\m代表男,W\\w代表女):");
// c = getchar();
scanf("%c",&c);
if(c == 'M' || c == 'm')
{
add_stu.sex = 'M';
break;
}
else if(c == 'W' || c == 'w')
{
add_stu.sex = 'W';
break;
}
else if(!isspace(c)) //--->isspace()是标准库中用来判断是不是空白字符的函数<---
{
printf("我去,这个学生是男的还是女的啊!\n");
}
}
//年级
while(1)
{
printf("请输入新增加学生的年级(0-20):");
val = InputTypeOfInt();
//scanf("%d",&val);
if(val>=0 && val <= 20)
break;
else
printf("这个学生这么叼,不符合常理吧!\n");
}
add_stu.grade = val;
//班级
printf("请输入新增加学生的班级(0-100):");
val = InputTypeOfInt();
//scanf("%d",&val);
add_stu._class = val;
////增加一条记录数据库操作///////
if(AddRecordUseMysql(add_stu) == 0)
{
printf("插入学生记录成功。\n");
return 0;
}
else
return -1;
}
//删除一个学生记录
int DeleteOneRecord(int *clc_flag)
{
*clc_flag = 1;
char c = 0;
int stu_num = 0,index = -1;
//输入学号
while(1)
{
printf("这位同学,请输入你要删除的学生的编号(0-10000):");
stu_num = InputTypeOfInt();
// scanf("%d",&stu_num);
if(IfStuNumExist(stu_num) == -1)
{
printf("这位同学,不好意思,你查找的学生不存在!\n");
printf("请重新输入或者取消本次操作(按Esc键取消,其他键重新输入)...");
c = getchar();
c = getch();
if(IsEsc(c) == 0)
{
printf("\n哎呀,取消本次操作了哦!\n");
*clc_flag = 1;
return -1;
}
else
printf("\n");
}
else
break;
}
///////////Mysql 数据库删除操作////////////
if(DeleteRecordUseMysql(stu_num) == 0)
{
printf("成功删除指定记录。\n");
return 0;
}
else
{
printf("删除记录失败!\n");
return -1;
}
}
//删除所有记录
int DeleteAllRecord()
{
char c;
printf("你真的想清除所有的学生记录吗?(Y/y确认删除,N/n取消返回)");
while(scanf("%c",&c))
{
if(c == 'Y' || c == 'y')
{
/////数据库删除操作//////
if(DeleteAllRecordUseMysql() == 0)
{
printf("成功删除所有记录。\n");
return 0;
}
}
else if(c == 'N' || c == 'n')
{
printf("取消删除!\n");
return -1;
}
}
return 0;
}
//查询显示一条记录
int ShowOneRecord(int *clc_flag)
{
int stu_num = 0,index = -1;
int c = 0;
Student stu;
*clc_flag = 1;
//输入学号
while(1)
{
printf("这位同学,请输入你要查询的学生的编号(0-10000):");
stu_num = InputTypeOfInt();
//scanf("%d",&stu_num);
if(IfStuNumExist(stu_num) == -1)
{
printf("这位同学,不好意思,你查找的学生不存在!\n");
printf("请重新输入或者取消本次操作(按Esc键取消,其他键重新输入)...");
c = getchar(); //接受回车
c = getch(); //判断是否按下ESC键
if(IsEsc(c) == 0)
{
printf("\n哎呀,取消本次操作了哦!\n");
*clc_flag = 1;
return false;
}
else
printf("\n");
}
else
break;
}
//////数据库查询操作////
if(SearchOneRecordUseMysql( stu_num,&stu) == 0)
{
//显示查询到的学生记录
ShowBeginline();
ShowStuInfo(&stu) ;
ShowEndLine();
return 0;
}
else
{
printf("查询失败!\n");
return -1;
}
}
//显示所有的学生信息
int ShowAllRecords()
{
Student ret_stus[MAX_STUDENT];
int num = 0; //数据库中学生人数
int i;
/////显示所有学生记录数据库操作//////
if(ShowAllRecordsUseMysql(ret_stus,&num) == 0)
{
ShowBeginLine();
for(i = 0;i<num;++i)
ShowStuInfo(ret_stus+i) ;
ShowEndLine();
return 0;
}
else
{
printf("查询所有记录失败。\n");
return -1;
}
}
//显示当前数据库中的人数及其他们的编号
int ShowCurStuNums()
{
int ret_id[MAX_STUDENT];
int num = 0; //数据库中学生人数
int i = 0;
if(ShowCurStuNumsUseMysql(ret_id,&num) == 0)
{
printf("当前数据库中的学生记录数为:%d\n",num);
printf("序号\t学号\n");
for(i = 0;i<num;++i)
printf("%d \t%d\n",i+1,ret_id[i]); //序号 学号
return 0;
}
else
{
printf("查询所有记录失败。\n");
return -1;
}
}
//修改学生信息
int ModifyRecord()
{
int stu_num = 0,index = -1,val = 0;
char c = 0;
Student mod_stu;
//输入学号
while(1)
{
printf("这位同学,请输入你要修改的学生的编号(0-10000):");
stu_num = InputTypeOfInt();
//scanf("%d",&stu_num);
if(IfStuNumExist(stu_num) == -1)
printf("这位同学,不好意思,你查找的学生不存在请重新输入!\n");
else
break;
}
//从数据中读出指定学号的记录
if(SearchOneRecordUseMysql(stu_num,&mod_stu) != 0)
{
printf("读取一条记录出错!\n");
return -1;
}
printf("目前要修改的学生的名字为:%s\n",mod_stu.name);
printf("你想修改成的名字为:");
scanf("%s",&mod_stu.name);
printf("目前要修改的学生的年龄为:%d\n",mod_stu.age);
//年龄
while(1)
{
printf("请输入修改后学生的年龄(5-40):");
val = InputTypeOfInt();
//scanf("%d",&val);
if(val>=5 && val <= 40)
break;
else
printf("学生的年龄应该在5-40岁之间哦!\n");
}
mod_stu.age = val;
printf("目前要修改的学生的性别为:%c\n",mod_stu.sex);
//性别
while(1)
{
printf("请输入要修改的的学生性别(M\\m代表男,W\\w代表女):");
//c = getchar();
scanf("%c",&c);
if(c == 'M' || c == 'm')
{
mod_stu.sex = 'M';
break;
}
else if(c == 'W' || c == 'w')
{
mod_stu.sex = 'W';
break;
}
else if(!isspace(c)) //--->isspace()是标准库中用来判断是不是空白字符的函数<---
{
printf("我去,这个学生是男的还是女的啊!\n");
}
}
printf("目前要修改的学生的年级为:%d\n",mod_stu.grade);
//年级
while(1)
{
printf("请输入要修改学生的年级(0-20):");
val = InputTypeOfInt();
//scanf("%d",&val);
if(val>=0 && val <= 20)
break;
else
printf("这个学生这么叼,不符合常理吧!\n");
}
mod_stu.grade = val;
printf("目前要修改的学生的班级为:%d\n",mod_stu._class);
//班级
printf("请输入要修改学生的班级(0-100):");
//scanf("%d",&val);
val = InputTypeOfInt();
mod_stu._class = val;
////////数据库修改操作操作///////
if(ModifyRecordUseMysql(&mod_stu) == -1) //将修改保存至文件中
{
printf("修改学生信息出错!\n");
return -1;
}
else
{
printf("成功修改学生信息.\n");
return 0;
}
}
其他的部分属于界面显示部分,不是重点,在这里就不贴了。需要了解的,可以点击资源页进行下载。
四、说明:
1. 本系统要想成功运行必须要有一个一直运行着的Mysql服务器。并进行相关配置:端口、访问权限、用户名等等。在代码中采用的是本人的云主机上的一个Mysql服务器。云主机IP为118.89.148.55。
2. 要保证程序的运行,首先得建立一个数据库,此处采用的是本人的云主机上的System数据库。在数据库中需要建立一个表students,其基本的表结构如下图所示:
- 制作这个系统本人采用的IDE是codeblocks。附上的工程文件也是Codeblocks工程文件,如果使用这个IDE应该可以直接打开运行。如果是使用其他的IDE,可以将源代码拷贝到相应的工程,重新编译运行。
- 此工程的源文件使用使用的是C++的源文件格即cpp,但是内容几乎全是C的语法,包括输入输出,所以移植时时可以当做C语言的工程使用。
- 由于本次系统是一个工程,所以本人在实现时为了尽量方便用户和系统的稳定性,在某些模块加了一些看似麻烦的代码的地方(比如说,用户选择完之后清空屏幕内容部分和在用户输入年龄、班级等整形类型的部分。)
- 随工程文件附上了Mysql的学习文件(Mysql必知必会)和Mysql的C语言API供大家学习使用。
- 其他的一些注意事项在代码中都有介绍。
- 本人能力有限,系统一定还有不完善的地方。如果大家发现,希望大家在博客中给我指出。我的csdn博客名为:BLSxiaopanlaile。
五、总结:
这个学生管理系统虽然很简单,但是通过编写这个系统,让我真真切切的了解到数据库发展的两个阶段(总共是三个阶段):文件系统和数据库管理系统。分别对应我以前编写的文件版本的学生管理系统。同时,通过编写一个系统软件,你需要尽可能的方便用户的使用,哪怕是多输入一个字符,或者少输入一个字符都很重要。还有,对于一个系统来说,尤其是面向用户的,还要保证其稳定性,也就是不能随随便便就崩了。虽然花了不少时间,确实还是学到不少东西。
注:完整的的代码可以点击资源页进行下载。
相关阅读
MySQL不支持 SELECT INTO FROM 语句解决方法
今天备份mysql 数据表的时候,发现mysql 竟然不支持select * into bk from user,运行sql 一直报错 ,错误代码:1327 Undeclared vari
CEILING(X) 或 CEIL(X) 该函数返回的最小整数值,但不能小于X。 SELECT CEILING(3.46);#4 SELECT CEIL(-6.43);#-6
存储过程简介SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用
Windows下的MySQL安装、MySQL-Front安装
全栈工程师开发手册 (作者:栾鹏) Mysql数据库系统软件的安装 访问“http://dev.mysql.com/downloads/windows/installer/”或ht
1. 创建相关目录 mkdir -p /data/330{7..9}/data 2. 创建配置文件 cat>> /data/3307/my.cnf<<EOF [mysqld] basedir