版权声明:本文为博主原创文章,未经博主允许不得转载。 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(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 |
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 查看本文章