最近开发个项目,因为要用到mysql数据库,作为对数据的后台支持,于是就找了些关于mysql c api的资料,发现不像以前用ado那么顺手,于是就按着操作ado的习惯,写了几个操作mysql数据库的类,用起来感觉还比较方便,小弟不敢独享,于 是就贴在了自己的blog上,与大家分享,希望大家多多测试,增加更多的功能 ........
忠告:这几个类对处理不是很大数据量的操作是比较理想的, 但对于特大型的数据查询时就不太适合了,因为我将查询到的数据直接放入了内存,如果一次查询的数据量超过了几百M,而你的内存没有足够大,就应该想想别的办法了!也希望大家帮忙改进,谢谢!
希望能帮你从繁忙的工作中解放出来,因为我们都是辛苦的程序员,共同进步,互相学习,我一直所希望的!
good luck
源码:
/*
* project:
* 通用模块 ( 用 c++ 处理 mysql 数据库类,像ADO )
*
* description:
*
* 通过DataBase,RecordSet,Record,Field类,实现对mysql数据库的操作
* 包括连接、修改、添加、删除、查询等等,像ADO一样操作数据库,使
* 用方便
*
* ( the end of this file have one sample,
* welcom to use... )
*
*
* file:zlb_mysql.h
*
* author: @ zlb
*
* time:2005-12-12
*
*
*
--*/
#ifndef ZLB_MYSQL_H
#define ZLB_MYSQL_H
#include "mysql.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
namespace zlb_mysql{
/*
* 字段操作
*/
class Field
{
public :
/* 字段名称 */
vector<string> m_name;
/* 字段类型 */
vector<enum_field_types> m_type;
public :
Field();
~Field();
/* 是否是数字 */
bool IsNum(int num);
/* 是否是数字 */
bool IsNum(string num);
/* 是否是日期 */
bool IsDate(int num);
/* 是否是日期 */
bool IsDate(string num);
/* 是否是字符 */
bool IsChar(int num);
/* 是否是字符 */
bool IsChar(string num);
/* 是否为二进制数据 */
bool IsBlob(int num);
/* 是否为二进制数据 */
bool IsBlob(string num);
/* 得到指定字段的序号 */
int GetField_NO(string field_name);
};
/*
* 1 单条记录
* 2 [int ]操作 [""]操作
*/
class Record
{
public:
/* 结果集 */
vector<string> m_rs;
/* 字段信息 占用4字节的内存 当记录数很大是回产生性能问题 */
Field *m_field;
public :
Record(){};
Record(Field* m_f);
~Record();
void SetData(string value);
/* [""]操作 */
string operator[](string s);
string operator[](int num);
/* null值判断 */
bool IsNull(int num);
bool IsNull(string s);
/* 用 value tab value 的形式 返回结果 */
string GetTabText();
};
/*
* 1 记录集合
* 2 [int ]操作 [""]操作
* 3 表结构操作
* 4 数据的插入修改
*/
class RecordSet
{
private :
/* 记录集 */
vector<Record> m_s;
/* 游标位置*/
unsigned long pos;
/* 记录数 */
int m_recordcount;
/* 字段数 */
int m_field_num;
/* 字段信息 */
Field m_field;
MYSQL_RES * res ;
MYSQL_FIELD * fd ;
MYSQL_ROW row;
MYSQL* m_Data ;
public :
RecordSet();
RecordSet(MYSQL *hSQL);
~RecordSet();
/* 处理返回多行的查询,返回影响的行数 */
int ExecuteSQL(const char *SQL);
/* 得到记录数目 */
int GetRecordCount();
/* 得到字段数目 */
int GetFieldNum();
/* 向下移动游标 */
long MoveNext();
/* 移动游标 */
long Move(long length);
/* 移动游标到开始位置 */
bool MoveFirst();
/* 移动游标到结束位置 */
bool MoveLast();
/* 获取当前游标位置 */
unsigned long GetCurrentPos()const;
/* 获取当前游标的对应字段数据 */
bool GetCurrentFieldValue(const char * sFieldName,char *sValue);
bool GetCurrentFieldValue(const int iFieldNum,char *sValue);
/* 获取游标的对应字段数据 */
bool GetFieldValue(long index,const char * sFieldName,char *sValue);
bool GetFieldValue(long index,int iFieldNum,char *sValue);
/* 是否到达游标尾部 */
bool IsEof();
/* 返回字段 */
Field* GetField();
/* 返回字段名 */
const char * GetFieldName(int iNum);
/* 返回字段类型 */
const int GetFieldType(char * sName);
const int GetFieldType(int iNum);
/* 返回指定序号的记录 */
Record operator[](int num);
};
/*
* 1 负责数据库的连接关闭
* 2 执行sql 语句(不返回结果)
* 3 处理事务
*/
class DataBase
{
public :
DataBase();
~DataBase();
private :
/* msyql 连接句柄 */
MYSQL* m_Data;
public :
/* 返回句柄 */
MYSQL * GetMysql();
/* 连接数据库 */
int Connect(string host, string user,
string passwd, string db,
unsigned int port,
unsigned long client_flag);
/* 关闭数据库连接 */
void DisConnect();
/* 执行非返回结果查询 */
int ExecQuery(string sql);
/* 测试mysql服务器是否存活 */
int Ping();
/* 关闭mysql 服务器 */
int ShutDown();
/* 主要功能:重新启动mysql 服务器 */
int ReBoot();
/*
* 说明:事务支持InnoDB or BDB表类型
*/
/* 主要功能:开始事务 */
int Start_Transaction();
/* 主要功能:提交事务 */
int Commit();
/* 主要功能:回滚事务 */
int Rollback();
/* 得到客户信息 */
const char * Get_client_info();
/* 主要功能:得到客户版本信息 */
const unsigned long Get_client_version();
/* 主要功能:得到主机信息 */
const char * Get_host_info();
/* 主要功能:得到服务器信息 */
const char * Get_server_info();
/*主要功能:得到服务器版本信息*/
const unsigned long Get_server_version();
/*主要功能:得到 当前连接的默认字符集*/
const char * Get_character_set_name();
/* 主要功能返回单值查询 */
char * ExecQueryGetSingValue(string sql);
/* 得到系统时间 */
const char * GetSysTime();
/* 建立新数据库 */
int Create_db(string name);
/* 删除制定的数据库*/
int Drop_db(string name);
};
};
#endif //ZLB_MYSQL_H
/*
* project:
* 通用模块 ( 用 c++ 处理 mysql 数据库类,像ADO )
*
* description:
*
* 通过DataBase,RecordSet,Record,Field类,实现对mysql数据库的操作
* 包括连接、修改、添加、删除、查询等等,像ADO一样操作数据库,使
* 用方便
*
* ( the end of this file have one sample,
* welcom to use... )
*
*
* file:zlb_mysql.cpp
*
* author: @ zlb
*
* time:2005-12-12
*
*
*
--*/
#include "stdafx.h"
#include "zlb_mysql.h"
namespace zlb_mysql{
/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/*
* 字段操作
*/
Field::Field(){}
Field::~Field(){}
/*
* 是否是数字
*/
bool Field::IsNum(int num)
{
if(IS_NUM(m_type[num]))
return true;
else
return false;
}
/*
* 是否是数字
*/
bool Field::IsNum(string num)
{
if(IS_NUM(m_type[GetField_NO(num)]))
return true;
else
return false;
}
/*
* 是否是日期
*/
bool Field::IsDate(int num)
{
if( FIELD_TYPE_DATE == m_type[num] ||
FIELD_TYPE_DATETIME == m_type[num] )
return true;
else
return false;
}
/* 是否是日期 */
bool Field::IsDate(string num)
{
int temp;
temp=GetField_NO(num);
if(FIELD_TYPE_DATE == m_type[temp] ||
FIELD_TYPE_DATETIME == m_type[temp] )
return true;
else
return false;
}
/*
* 是否是字符
*/
bool Field::IsChar(int num)
{
if(m_type[num]==FIELD_TYPE_STRING ||
m_type[num]==FIELD_TYPE_VAR_STRING ||
m_type[num]==FIELD_TYPE_CHAR )
return true;
else
return false;
}
/*
* 是否是字符
*/
bool Field::IsChar(string num)
{
int temp;
temp=this->GetField_NO (num);
if(m_type[temp]==FIELD_TYPE_STRING ||
m_type[temp]==FIELD_TYPE_VAR_STRING ||
m_type[temp]==FIELD_TYPE_CHAR )
return true;
else
return false;
}
/*
* 是否为二进制数据
*/
bool Field::IsBlob(int num)
{
if(IS_BLOB(m_type[num]))
return true;
else
return false;
}
/*
* 是否为二进制数据
*/
bool Field::IsBlob(string num)
{
if(IS_BLOB(m_type[GetField_NO(num)]))
return true;
else
return false;
}
/*
* 得到指定字段的序号
*/
int Field::GetField_NO(string field_name)
{
for(unsigned int i=0;i<m_name.size ();i++)
{
if(!m_name[i].compare (field_name))
return i;
}
return -1;
}
/*-----------------------------------------------------*/
/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/*
* 1 单条记录
* 2 [int ]操作 [""]操作
*/
Record::Record(Field * m_f)
{
m_field =m_f;
}
Record::~Record(){};
void Record::SetData(string value)
{
m_rs.push_back (value);
}
/* [""]操作 */
string Record::operator[](string s)
{
return m_rs[m_field->GetField_NO(s)];
}
string Record::operator[](int num)
{
return m_rs[num];
}
/* null值判断 */
bool Record::IsNull(int num)
{
if("" == m_rs[num].c_str ())
return true;
else
return false;
}
bool Record::IsNull(string s)
{
if("" == m_rs[m_field->GetField_NO(s)].c_str())
return true;
else return false;
}
/* 主要-功能:用 value tab value 的形式 返回结果 */
string Record::GetTabText()
{
string temp;
for(unsigned int i=0 ;i<m_rs.size();i++)
{
temp+=m_rs[i];
if(i<m_rs.size ()-1)
temp+="\t";
}
return temp;
}
/*-----------------------------------------------------*/
/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/*
* 1 记录集合
* 2 [int ]操作 [""]操作
* 3 表结构操作
* 4 数据的插入修改
*/
RecordSet::RecordSet()
{
res = NULL;
row = NULL;
pos = 0;
}
RecordSet::RecordSet(MYSQL *hSQL)
{
res = NULL;
row = NULL;
m_Data = hSQL;
pos = 0;
}
RecordSet::~RecordSet()
{
}
/*
* 处理返回多行的查询,返回影响的行数
* 成功返回行数,失败返回-1
*/
int RecordSet::ExecuteSQL(const char *SQL)
{
if ( !mysql_real_query(m_Data,SQL,strlen(SQL)))
{
//保存查询结果
res = mysql_store_result(m_Data );
//得到记录数量
m_recordcount = (int)mysql_num_rows(res) ;
//得到字段数量
m_field_num = mysql_num_fields(res) ;
for (int x = 0 ; fd = mysql_fetch_field(res); x++)
{
m_field.m_name.push_back(fd->name);
m_field.m_type.push_back(fd->type);
}
//保存所有数据
while (row = mysql_fetch_row(res))
{
Record temp(&m_field);
for (int k = 0 ; k < m_field_num ; k++ )
{
if(row[k]==NULL||(!strlen(row[k])))
{
temp.SetData ("");
}
else
{
temp.SetData(row[k]);
}
}
//添加新记录
m_s.push_back (temp);
}
mysql_free_result(res ) ;
return m_s.size();
}
return -1;
}
/*
* 向下移动游标
* 返回移动后的游标位置
*/
long RecordSet::MoveNext()
{
return (++pos);
}
/* 移动游标 */
long RecordSet::Move(long length)
{
int l = pos + length;
if(l<0)
{
pos = 0;
return 0;
}else
{
if(l >= m_s.size())
{
pos = m_s.size()-1;
return pos;
}else
{
pos = l;
return pos;
}
}
}
/* 移动游标到开始位置 */
bool RecordSet::MoveFirst()
{
pos = 0;
return true;
}
/* 移动游标到结束位置 */
bool RecordSet::MoveLast()
{
pos = m_s.size()-1;
return true;
}
/* 获取当前游标位置 */
unsigned long RecordSet::GetCurrentPos()const
{
return pos;
}
/* 获取当前游标的对应字段数据 */
bool RecordSet::GetCurrentFieldValue(const char * sFieldName,
char *sValue)
{
strcpy(sValue,m_s[pos][sFieldName].c_str());
return true;
}
bool RecordSet::GetCurrentFieldValue(const int iFieldNum,char *sValue)
{
strcpy(sValue,m_s[pos][iFieldNum].c_str());
return true;
}
/* 获取游标的对应字段数据 */
bool RecordSet::GetFieldValue(long index,const char * sFieldName,
char *sValue)
{
strcpy(sValue,m_s[index][sFieldName].c_str());
return true;
}
bool RecordSet::GetFieldValue(long index,int iFieldNum,char *sValue)
{
strcpy(sValue,m_s[index][iFieldNum].c_str());
return true;
}
/* 是否到达游标尾部 */
bool RecordSet::IsEof()
{
return (pos == m_s.size())?true:false;
}
/*
* 得到记录数目
*/
int RecordSet::GetRecordCount()
{
return m_recordcount;
}
/*
* 得到字段数目
*/
int RecordSet::GetFieldNum()
{
return m_field_num;
}
/*
* 返回字段
*/
Field * RecordSet::GetField()
{
return &m_field;
}
/* 返回字段名 */
const char * RecordSet::GetFieldName(int iNum)
{
return m_field.m_name.at(iNum).c_str();
}
/* 返回字段类型 */
const int RecordSet::GetFieldType(char * sName)
{
int i = m_field.GetField_NO(sName);
return m_field.m_type.at(i);
}
const int RecordSet::GetFieldType(int iNum)
{
return m_field.m_type.at(iNum);
}
/*
* 返回指定序号的记录
*/
Record RecordSet::operator[](int num)
{
return m_s[num];
}
/* -------------------------------------------------- */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/*
* 1 负责数据库的连接关闭
* 2 执行sql 语句(不返回结果)
* 3 处理事务
*/
DataBase::DataBase()
{
m_Data = NULL;
}
DataBase::~DataBase()
{
if(NULL != m_Data)
{
DisConnect();
}
}
/* 返回句柄 */
MYSQL * DataBase::GetMysql()
{
return m_Data;
}
/*
* 主要功能:连接数据库
* 参数说明:
* 1 host 主机ip地址或者时主机名称
* 2 user 用户名
* 3 passwd 密码
* 4 db 欲连接的数据库名称
* 5 port 端口号
* 6 uinx 嵌套字
* 7 client_flag 客户连接参数
* 返回值: 0成功 -1 失败
*/
int DataBase::Connect(string host, string user,
string passwd, string db,
unsigned int port,
unsigned long client_flag)
{
if((m_Data = mysql_init(NULL)) &&
mysql_real_connect( m_Data, host.c_str(),
user.c_str(), passwd.c_str(),
db.c_str(),port , NULL,
client_flag))
{
//选择制定的数据库失败
if ( mysql_select_db( m_Data, db.c_str () ) < 0 )
{
mysql_close( m_Data) ;
return -1 ;
}
}
else
{
//初始化mysql结构失败
mysql_close( m_Data );
return -1 ;
}
//成功
return 0;
}
/*
* 关闭数据库连接
*/
void DataBase::DisConnect( )
{
mysql_close(m_Data) ;
}
/*
* 主要功能: 执行非返回结果查询
* 参数:sql 待执行的查询语句
* 返回值; n为成功 表示受到影响的行数 -1 为执行失败
*/
int DataBase::ExecQuery(string sql)
{
if(!mysql_real_query(m_Data,sql.c_str (),(unsigned long)sql.length()) )
{
//得到受影响的行数
return (int)mysql_affected_rows(m_Data) ;
}
else
{
//执行查询失败
return -1;
}
}
/*
* 主要功能:测试mysql服务器是否存活
* 返回值:0 表示成功 -1 失败
*/
int DataBase::Ping()
{
if(!mysql_ping(m_Data))
return 0;
else
return -1;
}
/*
* 主要功能:关闭mysql 服务器
* 返回值;0成功 -1 失败
*/
int DataBase::ShutDown()
{
if(!mysql_shutdown(m_Data,SHUTDOWN_DEFAULT))
return 0;
else
return -1;
}
/*
* 主要功能:重新启动mysql 服务器
* 返回值;0表示成功 -1 表示失败
*/
int DataBase::ReBoot()
{
if(!mysql_reload(m_Data))
return 0;
else
return -1;
}
/*
* 说明:事务支持InnoDB or BDB表类型
*/
/*
* 主要功能:开始事务
*/
int DataBase::Start_Transaction()
{
if(!mysql_real_query(m_Data, "START TRANSACTION" ,
(unsigned long)strlen("START TRANSACTION") ))
{
return 0;
}
else
//执行查询失败
return -1;
}
/*
* 主要功能:提交事务
* 返回值:0 表示成功 -1 表示失败
*/
int DataBase::Commit()
{
if(!mysql_real_query( m_Data, "COMMIT",
(unsigned long)strlen("COMMIT") ) )
{
return 0;
}
else
//执行查询失败
return -1;
}
/*
* 主要功能:回滚事务
* 返回值:0 表示成功 -1 表示失败
*/
int DataBase::Rollback()
{
if(!mysql_real_query(m_Data, "ROLLBACK",
(unsigned long)strlen("ROLLBACK") ) )
return 0;
else
//执行查询失败
return -1;
}
/* 得到客户信息 */
const char * DataBase::Get_client_info()
{
return mysql_get_client_info();
}
/*主要功能:得到客户版本信息*/
const unsigned long DataBase::Get_client_version()
{
return mysql_get_client_version();
}
/* 主要功能:得到主机信息 */
const char * DataBase::Get_host_info()
{
return mysql_get_host_info(m_Data);
}
/* 主要功能:得到服务器信息 */
const char * DataBase::Get_server_info()
{
return mysql_get_server_info( m_Data );
}
/* 主要功能:得到服务器版本信息 */
const unsigned long DataBase::Get_server_version()
{
return mysql_get_server_version(m_Data);
}
/*主要功能:得到 当前连接的默认字符集*/
const char * DataBase::Get_character_set_name()
{
return mysql_character_set_name(m_Data);
}
/*
* 主要功能返回单值查询
*/
char * DataBase::ExecQueryGetSingValue(string sql)
{
MYSQL_RES * res;
MYSQL_ROW row ;
char *p = NULL;
if(!mysql_real_query( m_Data, sql.c_str(),(unsigned long)sql.length()))
{
//保存查询结果
res = mysql_store_result( m_Data ) ;
row = mysql_fetch_row( res ) ;
p = ((row[0]==NULL)||(!strlen(row[0])))?"-1":row[0];
mysql_free_result( res ) ;
}
else
//执行查询失败
p = "-1";
return p;
}
/*
* 得到系统时间
*/
const char * DataBase::GetSysTime()
{
return ExecQueryGetSingValue("select now()");
}
/*
* 主要功能:建立新数据库
* 参数:name 为新数据库的名称
* 返回:0成功 -1 失败
*/
int DataBase::Create_db(string name)
{
string temp ;
temp="CREATE DATABASE ";
temp+=name;
if(!mysql_real_query( m_Data,temp.c_str () ,
(unsigned long)temp.length ()) )
return 0;
else
//执行查询失败
return -1;
}
/*
* 主要功能:删除制定的数据库
* 参数:name 为欲删除数据库的名称
* 返回:0成功 -1 失败
*/
int DataBase::Drop_db(string name)
{
string temp ;
temp="DROP DATABASE ";
temp+=name;
if(!mysql_real_query( m_Data,temp.c_str () ,
(unsigned long)temp.length ()) )
return 0;
else
//执行查询失败
return -1;
}
/*-----------------------------------------------------*/
};
/*
* 使用例子
*/
#include "zlb_mysql.h"
using namespace std;
void main()
{
zlb_mysql::DataBase zlb;
//连接数据库
if(-1 == zlb.Connect("localhost"/*本地数据库,可以是远程 ip*/,
"root"/*用户名*/,"apple"/*密码*/,
"test"/*数据库名*/,
0,0/*两个标志,mysql文档有说明,一般为0*/))
{
std::cout<<"connect failed "<<std::endl;
}
else
{
std::cout<<"connect success"<<std::endl;
}
//通过返回的数据库句柄,建立记录急,你可以通过返回的这个句柄建立多个记录急
zlb_mysql::RecordSet rs(zlb.GetMysql());
rs.ExecuteSQL("select * from testtable");//这个语句大家都知道是什么意思了
cout<<rs.GetRecordCount()/*返回的总的记录数*/<<endl;
cout<<rs.GetFieldNum()/*返回的总的字段数*/<<endl;
cout<<rs[0].GetTabText()/*返回第一条记录,你也可以rs[1].GetTabText()
如果你有多条记录,
*/
<<endl;
/*实现遍列,也可以使用后面的遍列方式*/
for(int i=0;i<rs.GetRecordCount();++i)
{
for(int j =0;j<rs.GetFieldNum();++j)
cout<<rs[i][j];
cout<<endl;
}
zlb_mysql::Field *fd = rs.GetField();/*你可以通过这样的方式,获取字段的信息*/
cout<<fd->GetField_NO("Password")/*返回我表里的 Password 字段的位置,不
是记录的位置*/
<<endl;
cout<<rs[0]["Password"]<<endl;/*输出第0行第Password列的值*/
cout<<rs[0][fd->GetField_NO("Password")]<<endl;/*你也可以这样*/
cout<<rs.GetFieldName(0)/*获取字段的名字*/<<endl;
cout<<rs.GetFieldType("UserName")/*获取字段的类型,是mysql里定义的*/<<endl;
cout<<rs.GetCurrentPos()/*获取当前记录的位置*/<<endl;
char s[50];
rs.GetCurrentFieldValue(1,s);/*获取当前记录对应字段的值*/
cout<<s<<endl;
cout<<rs.Move(1)<<endl;/*移动游标,正数往前 负数往后*/
cout<<rs.GetCurrentPos()<<endl;
rs.GetCurrentFieldValue(1,s);
cout<<s<<endl;
rs.MoveFirst();/*移动游标到最前*/
while(!rs.IsEof()/*判断是否到达游标尾,实现遍列*/)
{
rs.GetCurrentFieldValue("UserName",s);
cout<<s<<"\t";
rs.GetCurrentFieldValue("Password",s);
cout<<s<<"\t\n";
rs.MoveNext();
}
rs.GetFieldValue(0,"UserName",s);/*获取指定行 的记录值*/
cout<<s<<"\t";
rs.GetFieldValue(0,"Password",s);
cout<<s<<"\t\n";
}
-------------
使用了一段时间后发现两处地方有问题,特添加修改如下:
1在函数int RecordSet::ExecuteSQL(const char *SQL)
{ //添加如下代码
m_field.m_name.clear();
m_field.m_type.clear();
m_recordcount = 0;
m_field_num = 0;
m_s.clear();
pos = 0;
//和以前一样
if ( !mysql_real_query(m_Data,SQL,strlen(SQL)))...........
2 函数bool RecordSet::MoveLast()
修改为:
bool RecordSet::MoveLast()
{
pos = m_s.size()-1;
if(pos <0)
pos = 0;
return true;
}