一,基本文件配置;
我用的时VS2017:
实验目的:
用Mysql为C提供的API封装出一个访问MySQL数据库的类。
引用API呢,简单说就是将MYSQL中include文件夹,libmysql.dll,libmysql.lib文件引入到项目中;最简单暴力的方法自然是通通给复制粘贴过来;
比较好的方法是在项目属性里配置好include目录、lib目录、libmysql.dll文件,最后把libmysql.dll文件给复制粘贴到和.cpp文件同级的目录下。只把前三个目录/文件引入配置中在运行时还是会报错找不到"libmysql.dll"文件。
在网上参考了很多教程,大多数的说法都是只配置好前三项,最后找到了一个比较靠谱一点的说法:
添加链接描述
是配置好前三项后再把libmysql.dll文件复制粘贴过来。
配置好后将解决方案平台改为“X64”
2,之后就可以开始运行了。
先进行一个运行测试:
当然主机名,和数据库要改成自己的
#include <iostream>
#include "mysql.h"
using namespace std;
int main()
{
MYSQL conn;
MYSQL_RES *res_set;
MYSQL_ROW row;
// 获得或初始化一个MYSQL结构
mysql_init(&conn);
// 连接一个MySQL服务器。
if (!mysql_real_connect(&conn, "主机", "用户名", "密码", "数据库名", 3306, NULL, 0))
{
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(&conn));
}
else
{
fprintf(stdout, "Successfully connected to Database.\n");
// 执行指定为一个空结尾的字符串的SQL查询。
int status = mysql_query(&conn, "SELECT 1 + 2");
// 检索一个完整的结果集合给客户。
res_set = mysql_store_result(&conn);
// 返回一个结果集合中的行的数量
int count = mysql_num_rows(res_set); printf("No of rows = %d\n", count);
while ((row = mysql_fetch_row(res_set)) != NULL) // 从结果集合中取得下一行
{
// 返回最近查询的结果列的数量。
for (int i = 0; i < mysql_num_fields(res_set); i++)
{
printf("%s \t", row[i] != NULL ? row[i] : "NULL"); // 第i列的值
}
printf("\n");
}
}
// 关闭数据库
mysql_close(&conn);
return 0;
}
首先我们来认识一下要用到的函数:
MYSQL conn;//定义一个Mysql结构
MYSQL_RES *res_set;//mysql查询结果的集合
MYSQL_ROW row;//其实实质上是一次数组
mysql_init(MYSQL *);//初始化mysql结构
mysql_real_connect(MYSQL *, "主机", "用户名", "密码", "数据库名", 3306, NULL, 0);//建立数据库连接
mysql_query(MYSQL*, char *sql);//最基础的数据库查询
mysql_store_result(MYSQL*);//将数据库中查询(mysql_query)得到的结果(集合)存放在MySQL_RES结构中,返回MYSQL_RES
mysql_num_rows(MYSQL_RES);//返回int,受影响的含函数
mysql_fetch_row(MYSQL_RES); //返回结果集(MYSQL_RES)的当前行的结果 ,返回MYSQL_ROW(数组);
mysql_free_result(MYSQL_RES);//查询完成时调用
mysql_close(MYSQL*);//关闭数据库连接
mysql_error(MYSQL*);//返回错误信息;
mysql_commit(MYSQL*);//提交事务在调用执行函数后
有5个类,一个接口
封装mysql类:
class Mysql {
public:
Mysql();//默认构造函数,对MYSQL进行初始化
Mysql( const char*host, const char*username, const char *password, const char *db);//带参数构造,对对象初始化,并调用连接函数连接数据库;
virtual ~Mysql();//析构函数,实现mysql_close(&mysql);
void Mysql_init();//自定义初始化函数,这里没怎么用
int Mysql_execute(const char *sql);//自定义执行函数
int Mysql_Query(const char *sql);//自定义查询函数
void Mysql_Connect(const char*host, const char*username, const char *password, const char *db);//自定义连接函数,调用mysql_real_connection(^)
private:
MYSQL mysql;//私有定义了MYSQL 结构对象
};
Mysql::Mysql() {
mysql_init(&mysql);
}
void Mysql::Mysql_Connect(const char*host, const char*username, const char *password, const char *db) {
if (mysql_real_connect(&mysql, host, username, password, db, 3306, NULL, 0)) {
cout << "数据库连接成功!" << endl;
}
else {
cout << " 数据库连接失败!" << endl;
cout << "错误信息" << mysql_error(&mysql) << endl;
exit(0);
}
cout << "_____________________" << endl;
}
Mysql::Mysql(const char*host, const char*username, const char *password, const char *db) {
mysql_init(&mysql);
Mysql_Connect(host, username, password, db);
}
Mysql::~Mysql() {
mysql_close(&mysql);
cout << "数据库关闭!" << endl;
}
int Mysql::Mysql_execute(const char *sql) {
if (mysql_query(&mysql, sql)) {//查询函数,成功返回零,否则返回错误类型非零值
cout << "更新失败:" << mysql_error(&mysql) << endl;
return -1;
}
int arr = mysql_affected_rows(&mysql);//返回受影响的行数
cout << "受影响的行数为:" << arr << endl;
mysql_commit(&mysql);//完成事务
return arr;
}
int Mysql::Mysql_Query(const char *sql) {
if (mysql_query(&mysql, sql)) {
cout << "查询失败:" << mysql_error(&mysql) << endl;
return -1;
}
MYSQL_RES *RES = mysql_store_result(&mysql);//返回结果集
MYSQL_ROW row;//定义
int count = mysql_num_rows(RES);//返回结果集中行数
cout << "查询到" << count << "条结果" << endl;
cout << "学号\t" << "姓名" << endl;
while ((row = mysql_fetch_row(RES)) != NULL) {//实质返回一次字节数组,并指向下一行
for (int i = 0; i < mysql_num_fields(RES);i++) {//返回结果集列数
if (row[i] != NULL) {
cout << row[i] << "\t";
}
else {
cout << NULL << " ";
}
}/*for*/
}/*while*/
cout << endl;
mysql_free_result(RES);//一定要释放
return count;
}
void Mysql::Mysql_init() {
mysql_init(&mysql);
}
//定义基本的学生信息类,便于对数据库(对学生表)的数据管理
class student {
public:
student();
~student();
int getsnum();
string getsname();
void setsnum(int snum);
void setsname(string name);
private:
int num;
string name;
};
student::student() {
}
student::~student() {
}
void student::setsnum(int num) {
this->num = num;
}
void student::setsname(string name) {
this->name = name;
}
int student::getsnum() {
return num;
}
string student::getsname() {
return name;
}
class Istudentdao {
public:
Istudentdao() {};//对构造函数先定义一下
~Istudentdao() {};//同上
virtual int insertStudent(student &stu)=0;//实现插入学生信息
virtual int updateStudent(int sno, student&stu)=0;实现修改学生信息
virtual int deleteStudent(int sno)=0;//实现删除学生信息
virtual int selectStudent() = 0;//实现查询所有学生信息
virtual int selectStudent(int sno) = 0;//重载实现查询特定学生信息
};
//这是一个纯接口,用来定义实现对数据库的操作函数
//这里就是具体实现了接口中的函数
class estudentdao :public Istudentdao {
public:
estudentdao();
~estudentdao();
virtual int insertStudent(student &stu);
virtual int updateStudent(int sno, student&stu);
virtual int deleteStudent(int sno);
virtual int selectStudent();
virtual int selectStudent(int sno);
private:
Mysql *ESTU;//对数据库的操作必须要有定义好的MYSQL
};
estudentdao::estudentdao() {
ESTU = new Mysql("localhost", "root", "root", "sell");
}
estudentdao::~estudentdao() {
}
int estudentdao::insertStudent(student&stu) {
string sql = "insert into student values(" + to_string(stu.getsnum()) + ",\'" + stu.getsname() + "'\)";//用student类定义好sql语句
int ret = ESTU->Mysql_execute(sql.c_str());//c_str()返回的是临时指针
return ret;
}
int estudentdao::deleteStudent(int sno) {
string sql = "delete from student where sno=" + to_string(sno);
int ret = ESTU->Mysql_execute(sql.c_str());//相同原理
return ret;
}
int estudentdao::updateStudent(int sno, student&stu) {
string sql = "update student set sno=" + to_string(stu.getsnum()) + ",sname=\'" + stu.getsname() + "'\ where sno=" + to_string(sno);
int ret = ESTU->Mysql_execute(sql.c_str());//同上
return ret;
}
int estudentdao::selectStudent() {
string sql = "select *from student";
int ret = ESTU->Mysql_Query(sql.c_str());//同上
return ret;
}
int estudentdao::selectStudent(int sno) {
string sql = "select " + to_string(sno) + "from student";
int ret = ESTU->Mysql_Query(sql.c_str());//同上
return ret;
}
//之前我们已经实现了接口,但这只是为了实现接口,重要的还是调用
class studentController {
public:
studentController();
studentController(Istudentdao *dao);//这里用接口作参数,依赖倒置,可以在管理层更灵活地调用修改执行方法,p:接口可能不止一种实现方法
~studentController();
int insertStudent(student &stu);
int updateStudent(int sno, student&stu);
int deleteStudent(int sno);
int selectStudent();
int selectStudent(int sno);//这些是基本上又实现了一遍
private:
Istudentdao *dao;
//之后依赖导致 Istudentdao *dao=new estudentdao();
};
studentController::studentController() {
}
studentController::studentController(Istudentdao *dao) {
this->dao = dao;
}
studentController::~studentController() {
if (dao != NULL) {
delete dao;
}
}
int studentController::insertStudent(student&stu) {
return this->dao->insertStudent(stu);
}
int studentController::deleteStudent(int sno) {
return this->dao->deleteStudent(sno);
}
int studentController::selectStudent() {
return this->dao->selectStudent();
}
int studentController::selectStudent(int sno) {
return this->dao->selectStudent(sno);
}
int studentController::updateStudent(int sno, student&stu) {
return this->dao->updateStudent(sno, stu);
}
//最后的类,用来设计程序功能
class view {
public:
view();
~view();
int viewAdd();
int viewUpdate();
int viewDelete();
int viewSelect();
private:
studentController *stucon;//对studentController依赖
};
view::view() {
this->stucon = new studentController(new estudentdao());//用实现类来替代接口
}
view::~view() {
if (!this->stucon) {
delete this->stucon;
}
}
int view::viewAdd() {
int sno;
string sname;
cout << "请输入学号" << endl;
cin >> sno;
cout << "请输入姓名" << endl;
cin >> sname;
student stu;
stu.setsnum(sno);
stu.setsname(sname);
this->stucon->insertStudent(stu);
return 1;
}
int view::viewDelete(){
int sno;
cout << "请输入要删除哪一行" << endl;
cin >> sno;
this->stucon->deleteStudent(sno);
return 1;
}
int view::viewUpdate() {
int sno;//修改前学生的学号
student stu;
cout << "输入修改前的学号(四位数):";
cin >> sno;
int sno_1;
string name_1;
cout << "输入修改后的学号(四位数):";
cin >> sno_1;
cout << "输入修改后的姓名:";
cin >> name_1;
stu.setsname(name_1);
stu.setsnum(sno_1);
this->stucon->updateStudent(sno, stu);
return 1;
}
int view::viewSelect() {
int sno;
cout << "请输入要查询的学号,按0查询所有" << endl;
cin >> sno;
if (0==sno) {
this->stucon->selectStudent();
}
else {
this->stucon->selectStudent(sno);
}
return 1;
}
int main() {
view view1;
int flag = 1;
int switch_on;
while (1 == flag) {
cout << "1.添加学生" << endl;
cout << "2.更新学生" << endl;
cout << "3.删除学生" << endl;
cout << "4.查询学生" << endl;
cout << "5.退出" << endl;
cout << "输入:";
cin >> switch_on;
switch (switch_on)
{
case 1:
view1.viewAdd();
break;
case 2:
view1.viewUpdate();
break;
case 3:
view1.viewDelete();
break;
case 4:
view1.viewSelect();
break;
case 5:
flag = 0;
break;
default:
break;
}
}
return 0;
}
//主方法:用来完成;
至此,C++ 连接Mysql 封装及基本管理的具体实现就结束了;
从这些函数中可以更清楚地了解到,c++的面向对象编程是怎样环环相扣的。