注意:
1、如果查询到的数据有多条需要把SQL语句重复执行。
2、执行完毕select语句并没有数据的时候请注意调用ClearResult函数进行记录集指针清理,不然下次同样的SQL执行会得到自己不要的数据。如果上次SQL语句和本次SQL语句不一样的话不存在这样的问题,内部会根据SQL对比不同的时候会自动清理旧的记录集数据。
代码:
mysql 类封装 头文件源码如下:
#pragma once
#include #include #include #include #include #include #include "mysql/mysql.h"
#include
#include #include #pragma comment(lib,"wsock32.lib")
#pragma comment(lib, "mysql_api/libmysql.lib ")
//mysql参考文档
/*
*本文件是提供一些经常使用接口
*时间:2014.07.31
*作者:吴建华
*邮箱:564154394@qq.com
*/
/*
*modify:
*2016.11.07
*吴建华
* 修改事项:
* 1、mysql获取记录集函数不支持多线程所以增加了锁解决了记录集被修改的bug
* 2、增加了mysql连接池类 并希望大量插入数据库的时候使用mysql事务处理方式
*/
/*
*MYSQL 字段类参照表
*整理者:吴建华
*/
/************************************************************************
类型值类型描述
MYSQL_TYPE_TINYTINYINT字段
MYSQL_TYPE_SHORTSMALLINT字段
MYSQL_TYPE_LONGINTEGER或INT字段
MYSQL_TYPE_INT24MEDIUMINT字段
MYSQL_TYPE_LONGLONGBIGINT字段
MYSQL_TYPE_DECIMALDECIMAL或NUMERIC字段
MYSQL_TYPE_NEWDECIMAL精度数学DECIMAL或NUMERIC
MYSQL_TYPE_FLOATFLOAT字段
MYSQL_TYPE_DOUBLEDOUBLE或REAL字段
MYSQL_TYPE_BITBIT字段
MYSQL_TYPE_TIMESTAMPTIMESTAMP字段
MYSQL_TYPE_DATEDATE字段
MYSQL_TYPE_TIMETIME字段
MYSQL_TYPE_DATETIMEDATETIME字段
MYSQL_TYPE_YEARYEAR字段
MYSQL_TYPE_STRINGCHAR字段
MYSQL_TYPE_VAR_STRINGVARCHAR字段
MYSQL_TYPE_BLOBBLOB或TEXT字段(使用max_length来确定最大长度)
MYSQL_TYPE_SETSET字段
MYSQL_TYPE_ENUMENUM字段
MYSQL_TYPE_GEOMETRYSpatial字段
MYSQL_TYPE_NULLNULL-type字段
MYSQL_TYPE_CHAR不再重视,用MYSQL_TYPE_TINY取代
************************************************************************/
/*
*用于变参类型 如:%d %s两种类型
*
*/
#define DATA_TYPE_INT4//整型
#define DATA_TYPE_CHARPTR1//char*类型
#define DATA_TYPE_INVALID0//无效类型
/*
*select接口区分字符类型和cstring类型
*/
enum e_strType{e_char=0, e_cstring};
/*
*CTools是提供一些常用的接口类
*时间:2014.07.31
*作者:吴建华
*/
namespace _TOOLS_
{
static CMutex g_mtxmysql;//mysql操作对象的互斥对象
static CMutex g_mtxMysqlPool;//mysql连接池的互斥对象
class CTools
{
public:
MYSQLMysql;//mysql对象
~CTools()
{
mysql_close( &Mysql );
};
CTools()
{
m_pResult = NULL;
m_bOpen = false;
};
/*
*数据库初始化操作
*
*参数:
*pIP:数据库IP地址
*pUser:数据库用户名
*pPwd:数据库密码
*pDatabase:数据库名称
*
*返回值:
*返回false表示初始化失败,true表示初始化成功
*
*/
bool initmysql(const char* pIP, const char* pUser, const char* pPwd, const char* pDatabase, unsigned short nPort = 3306 );
/*
*执行数据库查询功能(带_s的标识支持CSting类型,不带的支持char*类型)
*参数:
*pSQL:SQL语句
*...:变参返回查询到的数据
*返回值:
*返回false表示数据库已经获取完毕,true表示数据还没有获取完毕
*/
bool select_sql_beack(__in const char *pSQL, __out ...);
bool select_sql_beack_s(__in const char *pSQL, __out ...);
/*
*修改/插入/删除功能
*参数:
*pSQL:SQL语句
*返回值:
*返回false表示执行失败,true表示执行成功
*
*/
bool update_sql(__in const char *pSQL);
bool insert_sql(__in const char *pSQL);
bool delete_sql(__in const char *pSQL);
/*
*执行查询SQL语句获取查询的数据
*
*参数:
*pSQL:sql语句
*ap:变参,是指输出查询到的数据
*
*返回值:
*返回false表示不是无效字符,非true表示是无效字符
*/
//打断上一次执行(意思就是不支持嵌套,嵌套可以使用上面的Select)
bool SelectBeack(__in const char *pSQL, e_strType, __out va_list ap);
/*
*清理记录集指针数据
*
*/
/*
*获取 MYSQL连接状态
*
*返回值:
*返回true 表示没有断开 返回false 表示mysql连接已经断开
*
*/
bool GetMysqlConnectStatus()
{
if (m_bOpen)
{
if( mysql_ping(&Mysql) == 0)//处于连接状态中
{
return true;
}
}
return m_bOpen;
}
/*
*清理查询后有多余的数据 最好执行sql语句后获取到所有需要数据后调用次接口清理
*/
void ClearResult()
{
if ( m_pResult!= NULL )
{
mysql_free_result(m_pResult);
m_pResult = NULL;
m_strOldSql = "";
}
//m_Lastmysql.initdata();
}
/*
*关闭mysql连接
*/
void CloseMysql(){
//if ( _pMysql )
{
mysql_close( &Mysql );
//_pMysql = NULL;
}
}
//是否自动提交
void AutoCommitSQL(BOOL bAuto = TRUE);
private:
bool execute(const char* pSQL);
private:
//MYSQL_INFO m_Lastmysql;
CString m_strOldSql;//旧的SQL语句
MYSQL_RES *m_pResult;//记录集
bool m_bOpen;
//公共接口
public:
static CString GetBinPath();
static WCHAR* ToWChar(char *str);
};
/************************************************************************/
/*MYSQL 连接池 */
/************************************************************************/
class mysql_connection_pool
{
public:
~mysql_connection_pool();
//单例模式
static mysql_connection_pool *GetInstance();
//初始化连接
size_t InitConnection(int nInitialSize=1);
//设置mysql信息
void SetMysqlInfo(const char* pIP,
const char* pUser,
const char* pPwd,
const char* pDatabase,
unsigned short nPort /* = 3306 */);
//获取msyql操作对象
CTools *GetConnection();
//回收连接对象
void ReleaseConnection(CTools * pObject);
//销毁连接池
void DestoryConnPool();
protected:
mysql_connection_pool();
private:
char m_szIP[128];
char m_szUser[128];
char m_szPwd[128];
char m_szDatabase[128];
short m_snPort;
std::queuethe_queue;
CMutex the_mutex;
};
}
mysql 操作类封装 实现文件源码如下:
#include "stdafx.h"
#include "tools.h"
#include using namespace _TOOLS_;
bool CTools::initmysql(const char* pIP,
const char* pUser,
const char* pPwd,
const char* pDatabase,
unsigned short nPort /* = 3306 */ )
{
//mysql初始化
mysql_init(&Mysql);
//连接数据库
if (!mysql_real_connect(&Mysql, pIP, pUser, pPwd, pDatabase, nPort, NULL, CLIENT_MULTI_STATEMENTS))
{
m_bOpen = false;
return m_bOpen;
}
mysql_query(&Mysql,"SET NAMES 'GBK'");
mysql_query(&Mysql, "set global max_connections=4000");//设置最大连接数量(mysql服务器默认为151 所以这里找到配置文件 只有这个办法咯)
mysql_options(&Mysql,MYSQL_READ_DEFAULT_GROUP,"IMServer");
m_bOpen = true;
return m_bOpen;
}
bool CTools::select_sql_beack(__in const char *pSQL, __out ...)
{
va_list ap;
va_start( ap, pSQL );
bool bRet = SelectBeack( pSQL,e_char,ap );
va_end( ap );
return bRet;
}
bool CTools::select_sql_beack_s(__in const char *pSQL, __out ...)
{
va_list ap;
va_start( ap, pSQL );
bool bRet = SelectBeack( pSQL,e_cstring,ap );
va_end( ap );
return bRet;
}
bool CTools::SelectBeack(__in const char *pSQL, e_strType nstrType, __out va_list ap)
{
MYSQL_ROW row;//数据
MYSQL_RES *pResult = NULL;//记录集指针
unsigned int num_fields;//字段个数
MYSQL_FIELD* pFields;//字段类型信息
if (!m_bOpen)
{
return false;
}
try
{
if (m_strOldSql.CompareNoCase(pSQL) != 0)
{
//没有查询过SQL新建查询
ClearResult();//清理记录集数据
g_mtxmysql.Lock();
if(!(mysql_query(&Mysql, pSQL) == 0) )
{
//查询失败
g_mtxmysql.Unlock();
return false;
}
//查询数据
pResult = mysql_use_result(&Mysql);
g_mtxmysql.Unlock();
int nCount = mysql_field_count(&Mysql);
if (!pResult)
{
return false;
}
m_strOldSql.Format("%s", pSQL);
}
else
{
pResult = m_pResult;
}
int *pnType = NULL;
CString *pstrType = NULL;
char * pszType = NULL;
num_fields = mysql_num_fields(pResult);
//获取一条数据
if(!(row = mysql_fetch_row(pResult)))
{
ClearResult();
return false;
}
for (unsigned int i=0; itype;
switch(nfieldtype)
{
//转整型 //这里有小数点的还没有做处理 需要进一步处理
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
{
pnType = va_arg(ap, int *);
if (pnType == NULL)
{
break;
}
if (row[i] == NULL)
{
*pnType = 0;
}
else
{
*pnType = atoi(row[i]);
}
}
break;
//转字符类型
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_VAR_STRING:
{
if (nstrType == e_cstring)
{
pstrType = va_arg(ap,CString *);
if (pstrType == NULL)
{
break;
}
if (row[i] == NULL)
{
*pstrType = "";
}
else
{
*pstrType = row[i];
}
}
else
{
pszType = va_arg(ap,char *);
if (pszType == NULL)
{
break;
}
if (row[i] == NULL)
{
pszType[0] = 0;
}
else
{
strcpy(pszType,row[i]);
}
}
}
break;
default:
{
// 我未预料到的类型。把参数指针向后移;
pszType = va_arg( ap, char *);
}
break;
}
}
}
catch (...)
{
ClearResult();
return false;
}
m_pResult = pResult;
return true;
}
bool CTools::execute(const char* pSQL)
{
ASSERT(pSQL);
try
{
int nRet = mysql_query(&Mysql, pSQL);
if ( nRet != 0 )
{
const char* pError=NULL;
pError = mysql_error(&Mysql);
TRACE("MYSQL错误提示%s\r\n",pError);
return false;
}
}
catch (...)
{
return false;
}
return true;
}
bool CTools::delete_sql(__in const char *pSQL)
{
return execute(pSQL);
}
bool CTools::update_sql(const char *pSQL)
{
return execute(pSQL);
}
bool CTools::insert_sql(const char *pSQL)
{
return execute(pSQL);
}
void _TOOLS_::CTools::AutoCommitSQL(BOOL bAuto /*= TRUE*/)
{
mysql_autocommit(&Mysql, bAuto);
}
CString CTools::GetBinPath()
{
CString sPath;
GetModuleFileName(NULL, sPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);
sPath.ReleaseBuffer();
int nPos;
nPos = sPath.ReverseFind('\\');
sPath = sPath.Left(nPos);
return sPath;
}
WCHAR* CTools::ToWChar(char *str)
{
static WCHAR buffer[1024];
memset(buffer, 0, 1024);
MultiByteToWideChar(CP_ACP, 0, str, strlen(str), buffer, 1024);
return buffer;
}
/************************************************************************/
/*MYSQL 连接池 */
/************************************************************************/
mysql_connection_pool::mysql_connection_pool()
{
}
mysql_connection_pool::~mysql_connection_pool()
{
DestoryConnPool();
}
mysql_connection_pool * mysql_connection_pool::GetInstance()
{
static mysql_connection_pool object;
return &object;
}
CTools * mysql_connection_pool::GetConnection()
{
g_mtxMysqlPool.Lock();
CTools *pMysqlobject = NULL;
if (the_queue.empty())
{
g_mtxMysqlPool.Unlock();
return pMysqlobject;
}
pMysqlobject = the_queue.front();
the_queue.pop();
g_mtxMysqlPool.Unlock();
return pMysqlobject;
}
size_t _TOOLS_::mysql_connection_pool::InitConnection(int nInitialSize/*=1*/)
{
ASSERT(nInitialSize > 0);
g_mtxMysqlPool.Lock();
for ( int i=0; iinitmysql(m_szIP, m_szUser, m_szPwd, m_szDatabase, m_snPort))
{
delete pObject;
pObject = NULL;
continue;
}
/*
* 使用者 批量执行SQL前需要执行START TRANSACTION语法使得事物开启
*
* 使用者 在需要批量SQL执行完成后方可执行COMMIT语法 使得数据一并提交
*/
pObject->AutoCommitSQL(FALSE);//关闭自动调教 采用事物提交
the_queue.push(pObject);
}
size_t nSize = the_queue.size();
g_mtxMysqlPool.Unlock();
return nSize;
}
void _TOOLS_::mysql_connection_pool::SetMysqlInfo(const char* pIP, const char* pUser, const char* pPwd, const char* pDatabase, unsigned short nPort /* = 3306 */)
{
ASSERT(pIP != NULL);
ASSERT(pUser != NULL);
ASSERT(pPwd != NULL);
ASSERT(pDatabase != NULL);
g_mtxMysqlPool.Lock();
memcpy(m_szIP, pIP, strlen(pIP));
memcpy(m_szUser, pUser, strlen(pUser));
memcpy(m_szPwd, pPwd, strlen(pPwd));
memcpy(m_szDatabase, pDatabase, strlen(pDatabase));
m_snPort = nPort;
g_mtxMysqlPool.Unlock();
}
void mysql_connection_pool::ReleaseConnection(CTools * pObject)
{
ASSERT(pObject);
g_mtxMysqlPool.Lock();
the_queue.push(pObject);
g_mtxMysqlPool.Unlock();
}
void mysql_connection_pool::DestoryConnPool() {
g_mtxMysqlPool.Lock();
if (!the_queue.empty())
{
CTools *pMysqlobject = the_queue.front();
the_queue.pop();
pMysqlobject->insert_sql("COMMIT");
delete pMysqlobject;
pMysqlobject = NULL;
}
g_mtxMysqlPool.Unlock();
}
下次在写如何使用这个类来进行mysql读写(异步读写mysql,事务处理实现批量插入数据库,连接池的使用方式)