C++数据库编程-Mysql API封装

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18108083/article/details/88233959

之前使用C++操作数据库非常麻烦,为了以后操作Mysql数据库可以方便点,专门花了一段时间再次研究Mysql 的官方C语言API,并使用C++封装成类,因为Mysql提供的C语言 API是跨平台的,所以本Mysql类也可以在Windows和Linux下同时使用,不过要使用对应平台的Mysql官方库(include目录和lib目录),欢迎交流和参考。

官方手册:https://dev.mysql.com/doc/refman/8.0/en/

Mysql 版本:8.0

Mysql数据库API封装类的实现

API封装类的实现主要包括两个类:XData类和XMysql类。其中XData类主要是用来描述数据库中一个字段的信息,包括字段的类型,字段的内容,字段的内容的大小;XMysql类则是真正地实现了对Mysql数据库的操作,包括连接数据库、自动重连、执行SQL语句(增删改查)、支持事务操作、支持存储过程,具体如下:

XData接口列表
操作 功能 对象
XData() 默认构造函数,使用成员初始值 XData
XData(const char* s) 使用字符串构造成员内容 XData
XData(const int* d) 使用整型构造成员内容 XData
LoadFile(const char* filename) 读取硬盘中二进制文件构造遍历内容 XData
SaveFile(const char* filename) 将变量中的二进制内容写入硬盘 XData
Drop() 释放LoadFile申请的空间 XData
XMysql接口列表
XMysql() 默认构造函数 XMysql
~XMysql() 默认析构函数 XMysql
Init() 初始化Mysql上下文 XMysql
Close() 清理Mysql占用的所有资源 XMysql
Conncet(const char*host,const char* user,const char* pass,const char*db,unsigned short port=3306,unsigned long flag=0) 数据库连接 XMysql
Query(const char *sql, unsigned long sqllen = 0) 执行sql语句  XMysql
Options(enum mysql_option option, const void *arg) Mysql参数的设定 XMysql
SetConnectTimeout(int sec) 设置连接超时时间 XMysql
SetReconnect(bool isre = true) 自动重连,默认不自动 XMysql
StoreResult() 返回全部结果 XMysql
UseResult() 开始接受结果,通过Fetch获取 XMysql
FreeResult() 释放结果集占用的空间 XMysql
FetchRow() 获取一行数据 XMysql
GetInsertSql(map<string,XData> kv,string table) 自动根据map生成insert SQL语句 XMysql
Insert(map<string, XData> kv, string table) 插入非二进制数据 XMysql
InsertBin(map<string, XData> kv, string table) 插入二进制数据 XMysql
GetUpdateSql(map<string, XData> kv, string table,string where) 获取Update数据的sql语句 XMysql
Update(map<string, XData> kv, string table, string where) 修改非二进制数据 XMysql
UpdateBin(map<string, XData> kv, string table, string where) 修改二进制数据 XMysql
StartTransaction() 开始事务 XMysql
StopTransactiom() 结束事务 XMysql
Commit() 事务提交 XMysql
Rollback() 回滚 XMysql

(1)XData.h

#pragma once
#include<iostream>
#include<mysql.h>
#include<vector>
#include<map>
#include<fstream>
using namespace std;

namespace XMYSQL {

	
	struct XData  //存放从结果集读出的一行数据 vector<XData>,XData只是一行中的一个字段
	{
		XData() = default;
		XData(const char* s) :data(s), size(strlen(s)) {}  
		XData(const int* d) :type(MYSQL_TYPE_LONG),data(reinterpret_cast<const char*>(d)),size(sizeof(int)) {}//支持插入整型

		bool LoadFile(const char* filename);//从磁盘读取二进制文件,内容写入到data,size,会在堆中申请内存,需要Drop进行释放
		bool SaveFile(const char* filename);//从数据库读取二进制文件,并保存到硬盘
		void Drop();						//释放LoadFile申请的空间(内存管理要十分慎重)

		enum_field_types type = MYSQL_TYPE_STRING;    //类型
		const char *data = 0;  //存放具体数据
		int size = 0;          //数据大小(int类型限制了文件最大大小,需要的话可改为long)

	};
}

(2)XData.cpp

#include"XData.h"
namespace XMYSQL {

	bool XData::LoadFile(const char* filename)
	{
		if (!filename)
			return false;
		//打开文件
		ifstream in(filename, ios::in | ios::binary);  
		if (!in.is_open())
		{
			cerr << "LoadFile " << filename << " failed!" << endl;
		}
		//文件大小
		in.seekg(0, ios::end);  //移到尾部进行读取大小
		size = in.tellg();
		in.seekg(0, ios::beg);

		//cout << filename << "the file'size is : " << size << endl;

		if (size <= 0)  //空文件
		{
			return false;
		}

		data = new char[size];  //申请内存
		int readed = 0;
		while (!in.eof())
		{
			in.read(const_cast<char *>(data), size - readed);
			if (in.gcount() > 0)
				readed += in.gcount();  //返回本次读的数据大小
			else
				break;
		}
		in.close();
		this->type = MYSQL_TYPE_BLOB;
		return true;
	}

	void XData::Drop()
	{
		delete data;
		data = nullptr;
	}

	bool XData::SaveFile(const char* filename)
	{
		if (!data||size <= 0)
		{
			return false;
		}
			
		fstream out(filename, ios::out | ios::binary);
		if (!out.is_open())
		{
			cout << "SaveFile failed!open failed! " << filename << endl;
			return false;
		}
		out.write(data, size);
		cout << "size is :" << size << endl;
		out.close();
		return true;
	}

}

(3)XMysql.h

#pragma once
#include"XData.h"
#include<iostream>
#include<mysql.h>
#include<vector>
#include<map>
#include<fstream>
using namespace std;

//命名空间开始
namespace XMYSQL {

	class XMysql
	{
	public:
		XMysql();
		~XMysql();

		bool Init();   //初始化mysql
		void Close();  //清理占用的所有资源

		//数据库连接(不考虑线程安全) flag:设置支持多条语句
		bool Conncet(const char*host,const char* user,const char* pass,const char*db,unsigned short port=3306,unsigned long flag=0);
		//执行sql语句 (if sqllen==0 使用strlen自动获取)
		bool Query(const char *sql, unsigned long sqllen = 0);
		//Mysql参数的设定(在Connect之前调用)
		bool Options(enum mysql_option option, const void *arg);
		//设置连接超时时间
		bool SetConnectTimeout(int sec);      
		//自动重连,默认不自动
		bool SetReconnect(bool isre = true);

		//结果集获取
		//1 返回全部结果
		bool StoreResult();
		//2 开始接受结果,通过Fetch获取
		bool UseResult();

		//释放结果集占用的空间
		void FreeResult();

		//获取一行数据
		vector<XData> FetchRow();

		//自动根据map生成insert SQL语句
		string GetInsertSql(map<string,XData> kv,string table);  //使用XData结构体是因为既能传字符串内容,也能传二进制内容到const char*

		//插入非二进制数据
		bool Insert(map<string, XData> kv, string table);

		//插入二进制数据
		bool InsertBin(map<string, XData> kv, string table);

		//获取Update数据的sql语句(输入为 关键字-值)
		string GetUpdateSql(map<string, XData> kv, string table,string where);

		//修改非二进制数据,返回更新影响的记录数,失败返回-1
		int Update(map<string, XData> kv, string table, string where);

		//修改二进制数据,返回更新影响的记录数,失败返回-1
		int UpdateBin(map<string, XData> kv, string table, string where);

		//开始事务
		bool StartTransaction();

		//结束事务
		bool StopTransactiom();
		
		//事务提交
		bool Commit();

		//回滚
		bool Rollback();


	protected:
		MYSQL *mysql = nullptr;   //mysql句柄	
		MYSQL_RES *result = nullptr;  //结果集
	};

}//命名空间结束

(4)XMysql.cpp

#include "XMysql.h"

namespace XMYSQL {

	XMysql::XMysql()
	{
	}

	XMysql::~XMysql()
	{
	}

	bool XMysql::Init()
	{
		Close();   //确保之前没资源
		cout << "XMysql::Init()" << endl;

		//新创建一个MYSQL对象
		mysql = mysql_init(0);  
		if (!mysql)
		{
			cerr << "mysql_init failed! " << endl;  //标准输入,标准输出,错误输出
		}
		return true;
	}

	void XMysql::Close()
	{
		cout << "XMysql::Close() " << endl;
		FreeResult();
		if (mysql)
		{
			mysql_close(mysql);
			mysql = nullptr;
		}
	}

	bool XMysql::Conncet(const char*host, const char* user, const char* pass, const char*db, unsigned short port, unsigned long flag)
	{
		if(!mysql&&!Init())
		{
			cerr << "Connect failed! mysql is not init! " << endl; 
			return false;
		}
		if (!mysql_real_connect(mysql, host, user, pass, db, port, 0, flag))
		{
			cerr << "mysql connect failed! " <<mysql_error(mysql)<< endl;
			return false;
		}
		cout << "mysql connect success! " << endl;
		return true;
	}

	bool XMysql::Query(const char *sql, unsigned long sqllen)
	{
		if (!mysql)
		{
			cerr << "Query failed! mysql is NULL! " << endl;
			return false;
		}
		if(!sql)
		{
			cerr << "Query failed! sql is NULL! " << endl;
			return false;
		}
		if (sqllen <= 0)
		{
			sqllen = (unsigned long)strlen(sql);
		}
		if (!sql)
		{
			cerr << "Query failed! sql is NULL! " << endl;
			return false;
		}
		int re = mysql_real_query(mysql, sql, sqllen);
		if (re != 0)
		{
			cerr << "mysql_real_query failed!" << mysql_error(mysql) << endl;
			return false;
		}
		return true;
	}

	bool XMysql::Options(enum mysql_option option, const void *arg)
	{
		if (!mysql)
		{
			cerr << "Option failed! mysql is NULL! " << endl;
			return false;
		}
		int re = mysql_options(mysql, option, arg);
		if (re != 0)
		{
			cerr << "mysql_options failed!" << mysql_error(mysql) << endl;
			return false;
		}
		return true;
	}

	bool XMysql::SetConnectTimeout(int sec)
	{
		return Options(MYSQL_OPT_CONNECT_TIMEOUT,&sec);
	}

	//自动重连,默认不自动
	bool XMysql::SetReconnect(bool isre)
	{

		return Options(MYSQL_OPT_RECONNECT,&isre);
	}

	bool XMysql::StoreResult()
	{
		if (!mysql)
		{
			cerr << "StoreResult failed! mysql is NULL! " << endl;
			return false;
		}
		FreeResult();
		result = mysql_store_result(mysql);  //获取结果集
		if (!result)
		{
			cerr << "mysql_store_result failed!" << mysql_error(mysql) << endl;
			return false;
		}
		return true;
	}

	//2 开始接受结果,通过Fetch获取
	bool XMysql::UseResult()
	{
		if (!mysql)
		{
			cerr << "UseResult failed! mysql is NULL! " << endl;
			return false;
		}
		FreeResult();
		result = mysql_use_result(mysql);  //获取结果集
		if (!result)
		{
			cerr << "mysql_use_result failed!" << mysql_error(mysql) << endl;
			return false;
		}
		return true;
	}

	void XMysql::FreeResult()
	{
		if (result)
		{
			mysql_free_result(result);
			result = nullptr;
		}
	}

	vector<XData> XMysql::FetchRow()
	{
		vector<XData> re;
		if (!result)
		{
			return re;
		}

		MYSQL_ROW row = mysql_fetch_row(result); //获取一行
		if (!row)
		{
			return re;
		}

		//获取列数
		int num = mysql_num_fields(result);
		unsigned long *lens = mysql_fetch_lengths(result);   //获取每个字段内容的大小
		for (int i = 0; i < num; i++)  //挨个将一行中的每个字段插入到vector
		{
			XData xdata;
			xdata.data = row[i];
			xdata.size = lens[i];
			re.push_back(xdata);   //插入形成一行
		}
		return re;

	}

	string XMysql::GetInsertSql(map<string, XData> kv, string table)
	{
		string sql = "";
		if (kv.empty() || table.empty())
			return "";
		//inser to t_video (name,size) values('name1','1024')
		sql = "insert into ";
		sql += "`"+table+"` ";
		string keys = "";
		string vals = "";
	
		//遍历key - value
		for (auto iter = kv.begin(); iter != kv.end(); iter++)
		{
			keys += "`";
			keys += iter->first;
			keys += "`,";

			vals += "'";
			vals += iter->second.data;
			vals += "',";
		}
		//去除keys 和vals结尾后的逗号
		keys.erase(keys.size() - 1);
		vals.erase(vals.size() - 1);
		sql += "("+keys+")";
		sql += "values";
		sql += "(" + vals + ")";

		return sql;
	}

	bool XMysql::Insert(map<string, XData> kv, string table)
	{
		if (!mysql)
		{
			cerr << "Insert failed! mysql is NULL! " << endl;
			return false;
		}

		//拼接生成sql语句
		string sql = GetInsertSql(kv, table);

		if (sql.empty())
		{
			cerr << "Insert failed! sql is NULL! " << endl;
			return false;
		}
		if (Query(sql.c_str()))
			return false;
		int num = mysql_affected_rows(mysql);
		if (num <= 0)
			return false;
		return true;
	}

	bool XMysql::InsertBin(map<string, XData> kv, string table)
	{
		string sql = "";
		if (kv.empty() || table.empty()||!mysql)
			return false;
		//insert to t_video (name,size) values(?,?)
		sql = "insert into ";
		sql += "`" + table + "` ";
		string keys = "";
		string vals = "";
		//绑定字段
		MYSQL_BIND bind[256] = { 0 };
		int i = 0;
		//遍历key - value
		for (auto iter = kv.begin(); iter != kv.end(); iter++)
		{
			keys += "`";
			keys += iter->first;
			keys += "`,";

			vals += "?,";
			bind[i].buffer = const_cast<char*>(iter->second.data);
			bind[i].buffer_length = iter->second.size;
			bind[i].buffer_type = iter->second.type;
			i++;
		}
		//去除keys 和vals结尾后的逗号
		keys.erase(keys.size() - 1);
		vals.erase(vals.size() - 1);
		sql += "(" + keys + ")";
		sql += "values";
		sql += "(" + vals + ")";

		//初始化上下文
		MYSQL_STMT *stmt = mysql_stmt_init(mysql);
		if (!stmt)
		{
			cerr << "mysql_stmt_init failed!" << mysql_error(mysql) << endl;
			return false;
		}

		//预处理
		if (mysql_stmt_prepare(stmt, sql.c_str(),sql.length())!=0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_prepare failed!11" << mysql_error(mysql) << endl;
			return false;
		}
		//绑定
		if (mysql_stmt_bind_param(stmt, bind) != 0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_bind_param failed! " << mysql_stmt_error(stmt) << endl;
			return false;
		}
		//执行
		if (mysql_stmt_execute(stmt) != 0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_execute failed! " << mysql_stmt_error(stmt) << endl;
			return false;
		}
		//释放资源
		mysql_stmt_close(stmt);

		return true;
	}

	string XMysql::GetUpdateSql(map<string, XData> kv, string table, string where)
	{
		string sql = "";
		if (kv.empty() || table.empty())
			return "";
		//update `t_video` set `name` = 'test_001' where `id`=`id`
		sql = "update ";
		sql += "`" + table + "`";
		sql += " set ";
		for (auto iter = kv.begin();iter != kv.end(); iter++)
		{
			sql += "`";
			sql += iter->first;
			sql += "`='";
			sql += iter->second.data;
			sql += "',";
		}
		sql.erase(sql.length() - 1);
		sql +=" where " +where;
		return sql;
	}

	int XMysql::Update(map<string, XData> kv, string table, string where)
	{
		if (!mysql)
		{
			return -1;
		}
		string sql = GetUpdateSql(kv, table, where);
		if (sql.empty())
		{
			return -1;
		}
		if (!Query(sql.c_str()))
		{
			return -1;
		}
		int num = mysql_affected_rows(mysql);

		return num;
	}

	int XMysql::UpdateBin(map<string, XData> kv, string table, string where)
	{
		if (!mysql)
		{
			return -1;
		}
		//update `t_video` set `data`=?,`name`=?,`size`=? where `id`='1'
		string sql = "";
		sql = "update ";
		sql += "`" + table + "`";
		sql += " set ";
		MYSQL_BIND bind[256] = { 0 };
		int i = 0;
		for (auto iter = kv.begin(); iter != kv.end(); iter++)
		{
			sql += "`";
			sql += iter->first;
			sql += "`=?,";
			bind[i].buffer = const_cast<char*>(iter->second.data);
			bind[i].buffer_length = iter->second.size;
			bind[i].buffer_type = iter->second.type;
			i++;
		}
		sql.erase(sql.length() - 1);
		sql += " where " + where;

		//初始化上下文
		MYSQL_STMT *stmt = mysql_stmt_init(mysql);
		if (!stmt)
		{
			cerr << "mysql_stmt_init failed!22" << mysql_error(mysql) << endl;
			return -1;
		}
		//预处理
		if (mysql_stmt_prepare(stmt, sql.c_str(), sql.length()) != 0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_prepare failed!22" << mysql_error(mysql) << endl;
			return -1;
		}
		//绑定
		if (mysql_stmt_bind_param(stmt, bind) != 0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_bind_param failed! " << mysql_stmt_error(stmt) << endl;
			return -1;
		}
		//执行
		if (mysql_stmt_execute(stmt) != 0)
		{
			mysql_stmt_close(stmt);
			cerr << "mysql_stmt_execute failed! " << mysql_stmt_error(stmt) << endl;
			return -1;
		}
		//释放资源

		int num = mysql_stmt_affected_rows(stmt);
		mysql_stmt_close(stmt);

		return num;
	}

	bool XMysql::StartTransaction()
	{
		return Query("SET AUTOCOMMIT = 0");
	
	}

	bool XMysql::StopTransactiom()
	{
		return Query("SET AUTOCOMMIT = 1");
	}

	bool XMysql::Commit()
	{
		return Query("COMMIT");
	}

	//回滚
	bool XMysql::Rollback()
	{
		return Query("ROLLBACK");
	}

}  //命名空间

(5)测试文件 main.cpp

#include<iostream>
#include"XMysql.h"

using namespace std;
using namespace XMYSQL;   //自定义库的命名空间(没冲突就用命名空间进行简写,有冲突就不用命名空间,改用XMYSQL::name())

int main()
{
	XMysql xmysql;
	//1 初始化mysql上下文
	xmysql.Init();

	//2 连接数据库
	xmysql.SetConnectTimeout(3);
	xmysql.SetReconnect(true);
	xmysql.Conncet("127.0.0.1","root","020513","mysqlTsetDb");
	
	//3 执行sql语句
	//3-1 创建表
	string sql = "";
	sql = "CREATE TABLE IF NOT EXISTS `t_video`\
	(`id` INT AUTO_INCREMENT,\
	`name` VARCHAR(1024),\
	`data` BLOB,\
	`size` INT,\
	PRIMARY KEY(`id`))";
	cout << xmysql.Query(sql.c_str()) << endl;

	//3-2 清空表数据(包括自增id)
	sql = "TRUNCATE t_video";
	cout << xmysql.Query(sql.c_str()) << endl;

	//3-3 自动重连
	//while(1)
	//	cout<<xmysql.Query(sql.c_str()) << endl;

	//3-4 插入多个记录
	//sql = "insert into `t_video` (`name`) values ('test001')";
	//xmysql.Query(sql.c_str());
	//xmysql.Query(sql.c_str());
	//xmysql.Query(sql.c_str());
	//xmysql.Query(sql.c_str());
	//xmysql.Query(sql.c_str());

	//3-5 使用StoreResult读取
	//sql = "select * from `t_video`";
	//xmysql.Query(sql.c_str());
	//xmysql.StoreResult();
	//for(;;)   //从结果集中获取所有行并打印
	//{	
	//	vector<XData> one_row;
	//	one_row = xmysql.FetchRow();    //获取一行
	//	if (!one_row.size())   //读完则退出
	//		break;
	//	for (auto e : one_row) //打印一行结果
	//	{
	//		if (e.data)  //非NULL则打印
	//			cout << e.data;
	//	}
	//	cout << endl;
	//}
	//xmysql.FreeResult();

	//3-6 使用UseResult方式读取
	//xmysql.Query(sql.c_str());
	//xmysql.UseResult();
	//xmysql.FreeResult();


	//3-7 插入非二进制内容
	//map<string, XData> kv;
	//kv.insert(make_pair("name", "test_001"));
	//kv.insert(make_pair("size", "1222"));
	////cout << xmysql.GetInsertSql(kv, "t_video").c_str() << endl;
	//xmysql.Insert(kv, "t_video");

	//3-8 插入二进制文件
	//map<string, XData> kv;
	//XData file;
	//file.LoadFile("mysql.jpg");  //读文件并更新data、size、type
	//kv.insert(make_pair("name", "mysql.jpg"));
	//kv.insert(make_pair("data", file));
	//kv.insert(make_pair("size", &file.size));
	//xmysql.InsertBin(kv, "t_video");
	//xmysql.InsertBin(kv, "t_video");
	//xmysql.InsertBin(kv, "t_video");
	//xmysql.InsertBin(kv, "t_video");
	//file.Drop();
	
	//3-9 读取二进制文件并存在硬盘
	//sql = "select * from `t_video`";
	//xmysql.Query(sql.c_str());
	//xmysql.StoreResult();
	//vector<XData> one_row;
	//one_row = xmysql.FetchRow();    //获取一行
	//string outFilename = "1out_";
	//outFilename += one_row[1].data;
	//cout << outFilename.c_str() << endl;
	//one_row[2].SaveFile(outFilename.c_str());
	//xmysql.FreeResult();

	//3-10 Update非二进制数据
	//map<string, XData> kv;
	//kv.insert(make_pair("name", "update_test_002.jpg"));
	//kv.insert(make_pair("size", "2000"));
	//string where = "`id` = '1'";
	//int re = xmysql.Update(kv, "t_video", where);
	//cout << re << endl;

	//3-11 Update二进制数据
	//map<string, XData> kv_new;
	//XData file_new;
	//file_new.LoadFile("mysql_1.jpg");  //读文件并更新data、size、type
	//kv_new.insert(make_pair("name", "mysql_1.jpg"));
	//kv_new.insert(make_pair("data", file_new));
	//kv_new.insert(make_pair("size", &file_new.size));
	//xmysql.UpdateBin(kv_new, "t_video","`id`='1'");
	//file_new.Drop();

	//3-12 使用事务插入多条记录
	map<string, XData> kv;
	xmysql.StartTransaction();   //事务开
	kv.insert(make_pair("name", "test_trans001"));
	xmysql.Insert(kv, "t_video");
	xmysql.Insert(kv, "t_video");
	xmysql.Insert(kv, "t_video");
	xmysql.Rollback();      //回滚
	xmysql.Insert(kv, "t_video");
	xmysql.Insert(kv, "t_video");
	xmysql.Commit();			//提交
	xmysql.StopTransactiom();   //事务关


	//4 清理资源
	xmysql.Close();
	system("pause");
	return 0;
}
扫描二维码关注公众号,回复: 5447652 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_18108083/article/details/88233959
今日推荐