1、  一般架构说明

图 1 架构层次图

一般应用系统数据库访问模块可大致分为两层,一层是对数据库连接、连接池和结果集等直接对数据库的操作的封装,由于libmysql提供的库函数是直接操作数据库的,所以这一层在本质上是直接操作数据库的一层;二是可以根据系统业务功能将系统与数据库的交互划分为几个子块,提供给系统其它模块与数据库交互的接口。如果是C/S结构的系统,客户端与数据库的交互还可以通过诸如RPC(Remote Procedure Call Protocol 远程过程调用协议)等协议调用服务端RPC处理模块来进行。

如上的设计一是隔离了外界与数据库的直接交互,提高了数据安全性;二是对libmysql提供的数据库操作接口众多,统一类操作有多种不同的方式,各自适用的场合不同,对其进行了整合,是为使其更适合本系统,提高了系统的稳定性和可用性,同时使上层对数据库的操作更为方便;三是按系统功能划分子模块降低了系统的耦合度,提高了系统的可扩展性。

另外,数据库直接交互层也分为三个小块,这样做的目的也是为了降低系统耦合度。其中数据库连接管理块仅负责数据库连接的维持及相应查询事物处理。数据库连接池管理块则是负责在系统初始化时创建一定数量的数据库连接,实际上就是建立两个连接队列(一个在用连接队列和一个空闲连接队列)并维护这两个队列。对于连接池的建立是为了避免在每一次操作数据库时都要建立数据库连接和释放数据库连接等耗时操作,提高系统性能。数据结果集的处理是专门负责将查询返回的结果按上层要求的方式提供给上层使用。

2、  数据库连接类的实现

本类主要是实现数据库连接的建立和释放,数据库选择,SQL语句的执行,事务的提交和回滚及数据库错误信息的获取等功能。其中数据库连接的建立与释放及查询语句的执行是本节叙述的重点。在libmysql提供的库中使用mysql_real_connect()可与MySQL数据库建立连接,但在这之前还需要对MYSQL实例进行初始化,其中MYSQL为MySQL的数据库连接句柄,具体实现过程如下。

a、使用mysql_init()创建MYSQL句柄实例;

b、根据数据库主机地址、用户名、用户密码、数据库名及端口号等连接信息使用mysql_real_connect()接口为MYSQL句柄实例建立数据库连接;

c、为已经建立数据库连接的MYSQL句柄实例选择字符集。

需要注意的是,当应用程序服务器和数据库服务器不在同一主机时,新安装的MySQL数据库处于安全考虑是不允许远程连接的,这就需要为相应的用户赋予远程访问的权限,可采用MySQL命令: 

GRANT EXECUTE ON DBName.TableName TO 'UserName'@'192.168.1.1' IDENTIFIED BY 'UserPassword';

其中“192.168.1.1”为远程主机的IP地址,使用“%”表示接受所有IP主机的远程访问。当然出于数据安全考虑,需要慎重执行。最终实现连接建立的代码如下: 

int CDBConnect::ConnectDB(const char *host, const char *user, const char *password, const char *db, unsigned int port)
{
if (m_pMySql != NULL)
{
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "m_pMySql 已经初始化\n");
}
return DATABASE_NOERROR;
} m_pMySql = mysql_init((MYSQL*)NULL); if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Fatal( __FILE__, __LINE__, "m_pMySql 初始化失败\n");
}
return DATABASE_ERROR_INIT_POOL;
} if (!mysql_real_connect(m_pMySql, host, user, password, db, port,NULL,0))
{
if( NULL != pLC )
{
pLC->Fatal( __FILE__, __LINE__, "数据库连接失败,%s\n", GetLastErrorMsg());
}
int iRet = mysql_errno(m_pMySql);
printf( "errno = %d\n", iRet );
if (iRet == 1045)
{
return DATABASE_ERROR_USERORPASSWORD;
}
return DATABASE_ERROR_GET_CONNECTION;
} if (mysql_set_character_set(m_pMySql, "gbk") != 0)
{
if( NULL != pLC )
{
pLC->Error( __FILE__, __LINE__, "数据库字符集设置失败,%s\n", GetLastErrorMsg());
}
return DATABASE_POOL_ERROR_SET_CHARACTER;
} return DATABASE_NOERROR;
} void CDBConnect::Release()
{
delete this;
} void CDBConnect::CloseConnect()
{
m_ResultSet.Close(); if (m_pMySql != NULL)
{
mysql_close(m_pMySql);
m_pMySql = NULL;
}
} void CDBConnect::CloseQuery()
{
m_ResultSet.Close();
} int CDBConnect::ConnctionTest()
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
else
{
return mysql_ping(m_pMySql);
}
} int CDBConnect::SelectDB(const char *szDB)
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
if (mysql_select_db(m_pMySql,szDB))
{
if( NULL != pLC )
{
pLC->Error( __FILE__, __LINE__, "选择数据库失败,%s\n", GetLastErrorMsg());
}
return -1/*DATABASE_POOL_ERROR_SELECT_DATABASE*/;
}
else
{
return DATABASE_NOERROR;
}
} int CDBConnect::AutoCommit(bool mode)
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
return mysql_autocommit(m_pMySql, mode);
} int CDBConnect::Commite()
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
return mysql_commit(m_pMySql);
} int CDBConnect::RollBack()
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
return mysql_rollback(m_pMySql);
} PIDBResultSet CDBConnect::ExcuteQuery(const char *szSql)
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return NULL;
}
if(mysql_query(m_pMySql, szSql))
{
if( NULL != pLC )
{
pLC->Error( __FILE__, __LINE__, "读数据库失败,%s\n", GetLastErrorMsg());
}
return NULL;
}
m_ResultSet.Reset(mysql_store_result(m_pMySql));
return &m_ResultSet;
} int CDBConnect::ExcuteSql(const char *szSql)
{
if (m_pMySql == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
}
return DATABASE_ERROR_INIT_POOL;
}
if(mysql_query(m_pMySql,szSql))
{
if( NULL != pLC )
{
pLC->Error( __FILE__, __LINE__, "SQL语句执行失败,%s\n", GetLastErrorMsg());
}
return DATABASE_ERROR_EXCUTE_QUERY;
}
return mysql_affected_rows(m_pMySql);
} int CDBConnect::ExcuteRealSql(const char *szSql, unsigned long ulSqlLen )
{
//这里添加参数检查语句
if( ulSqlLen <= 0 )
{
//这里添加日志打印语句 }
if (m_pMySql == NULL)
{
//这里添加日志打印语句
return DATABASE_ERROR_EXCUTE_QUERY;
}
if(mysql_real_query(m_pMySql,szSql, ulSqlLen))
{
//这里添加日志打印语句
return DATABASE_ERROR_EXCUTE_QUERY;
}
return mysql_affected_rows(m_pMySql);
} const char* CDBConnect::GetLastErrorMsg()
{
if (m_pMySql != NULL)
{
return mysql_error(m_pMySql);
}
else
{
return NOT_CONNECT_DATABASE;
}
} int CDBConnect::GetLastInsertID(int *pInsertID)
{
if (m_pMySql != NULL)
{
*pInsertID = mysql_insert_id(m_pMySql); return DATABASE_NOERROR;
}
else
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMySql 没有初始化\n");
} return DATABASE_ERROR_INIT_POOL;
}
} unsigned long CDBConnect::EscapeRealToString( char *pDst, const char *pSrc, unsigned long ulSrcLen )
{
//这里添加参数检查代码…
if( ulSrcLen <= 0 )
{
//这里添加日志打印语句
} if (m_pMySql == NULL)
{
//这里添加日志打印语句
return DATABASE_ERROR_INIT_POOL;
}
return mysql_real_escape_string(m_pMySql,pDst, pSrc, ulSrcLen);
}

3、  数据库连接池类的实现

本类实现了连接池的建立和销毁,连接池运行状态信息的获取,从连接池中取出可用数据库连接及将短时间内不再使用的数据库连接放回连接池等操作。本类的架构实现关系到数据库的访问速度,攸关整个系统性能。同时为了维护连接池的安全性,保证在同一时间内只有一个线程能操作连接池,同一个连接也只能被一个线程使用,涉及到设置临界区和信号量等操作,下面将逐一详述。

a、数据结构描述 

typedef std::list<PIDBConnect> CONNECTION_HANDLE_LIST;
typedef std::list<PIDBConnect>::iterator ITER_CONNECTION_HANDLE_LIST;
class CDBConnectPool
{
private:
string m_host; //主机
string m_user; //用户名
string m_password; //密码
string m_db; //数据库名
unsigned int m_port; //端口
unsigned int m_connNum; //连接池的大小 CONNECTION_HANDLE_LIST m_lsBusyList; //正在使用的连接句柄,队列模型
CONNECTION_HANDLE_LIST m_lsIdleList; //未使用的连接句柄,队列模型 CRITICAL_SECTION m_csList; //临界值句柄
HANDLE m_hSemaphore; //信号量句柄
static CDBConnectPool *pConnPool; //单例模式
}

b、连接池的建立

在连接池建立时,首先应跟据用户要求建立连接的数量创建相应数量信号量,在逐个新建连接并放入空闲连接队列,其中任何一个连接创建失败都将导致整个连接池的建立失败。具体实现如下: 

int CDBConnectPool::Connect()
{
//同时打开connNum个连接
int ret = 0;
if (m_hSemaphore != NULL)
{
return DATABASE_ERROR;
}
m_hSemaphore = CreateSemaphore(NULL, m_connNum, m_connNum, NULL);
if (m_hSemaphore == NULL)
{
return DATABASE_POOL_ERROR_INIT_SEMAPHORE;
}
int i = 0;
for ( i=0; i<m_connNum; ++i)
{
CDBConnect *pConn = new CDBConnect();
ret = pConn->ConnectDB(m_host.c_str(), m_user.c_str(), m_password.c_str(), m_db.c_str(), m_port);
if(ret<0)
{
break;
}
m_lsIdleList.push_back(pConn);
}
if (i != m_connNum)
{
Close();
if (ret == DATABASE_ERROR_USERORPASSWORD)
{
return ret;
}
return DATABASE_ERROR_INIT_POOL;
}
return DATABASE_NOERROR;
}

c、关闭连接池

连接池的关闭与创建过程恰好相反,首先应关闭所有数据库连接,包括在用的和未用的,再清空队列(空闲连接队列和在用连接队列),最后清除信号量。实现代码如下: 

void CDBConnectPool::Close()
{
ITER_CONNECTION_HANDLE_LIST iter;
for (iter = m_lsBusyList.begin(); iter != m_lsBusyList.end(); iter++)
{
PIDBConnect pConn = *iter;
if( pConn != NULL )
{
pConn->CloseConnect();
pConn->Release();
}
}
m_lsBusyList.clear();
for (iter = m_lsIdleList.begin(); iter != m_lsIdleList.end(); iter++)
{
PIDBConnect pConn = *iter;
if( pConn != NULL )
{
pConn->CloseConnect();
pConn->Release();
};
}
m_lsIdleList.clear();
if( m_hSemaphore != NULL )
{
CloseHandle(m_hSemaphore);
m_hSemaphore = NULL;
}
}

d、从连接池中获取可用连接

在从连接池中取出连接时,首先等待信号量,直到有可用连接或者等待超时返回(避免线程死锁),然后进入临界区,即对两个队列的操作区域,防止在取连接时有其它线程也来去连接或是放连接回池,接着离开临界区,通知其它等待线程可操作临界区。另外比较重要的一点是,为确保我们取到的连接是真正可用的连接,在从空闲连接队列中取出连接并放入忙连接队列后需要测试我们得到的连接是否连通,未连通时应尝试重连,若重连依然失败,则应返回空。实现代码如下: 

PIDBConnect CDBConnectPool::GetConnection(int iTimeOut)
{
int ret;
PIDBConnect pConn = NULL;
DWORD dwWaitResult; dwWaitResult = WaitForSingleObject(m_hSemaphore, iTimeOut);
if (dwWaitResult != WAIT_OBJECT_0)
{
return NULL;
}
EnterCriticalSection(&m_csList);
if (m_lsIdleList.size() > 0)
{
pConn = m_lsIdleList.front();
m_lsIdleList.pop_front();
m_lsBusyList.push_back(pConn);
}
else
{
pConn = NULL;
}
LeaveCriticalSection(&m_csList); if (pConn->ConnctionTest() != 0)
{
char strError[1000] = {0};
strncpy(strError, pConn->GetLastErrorMsg(), 999);
strError[999] = '\0';
pConn->CloseConnect();
ret = pConn->ConnectDB(m_host.c_str(), m_user.c_str(),
m_password.c_str(), m_db.c_str(), m_port);
if (ret < 0)
{
BackToPool(pConn);
return NULL;
}
}
return pConn;
}

e、将未用连接放回连接池 

void CDBConnectPool::BackToPool(PIDBConnect pConn)
{
pConn->CloseQuery();
pConn->AutoCommit(true);
EnterCriticalSection(&m_csList);
ReleaseSemaphore(m_hSemaphore, 1, NULL);
m_lsBusyList.remove(pConn);
m_lsIdleList.push_back(pConn);
LeaveCriticalSection(&m_csList);
}

4、  数据库结果集类的实现

本类主要实现对查询返回结果的一系列操作,包含查找指定数据、取得记录数、获得下一条记录及根据字段名或是字段在结果集中的ID获取字段等。直接给出源码如下:

头文件: 

/////////////////////////////////////////////////////////////////////////////////
/// Copyright (C), 2011
/// \file DBResultSet.h
/// \brief DATABASE数据库结果集接口
/// \author hkp(horace20@live.cn)
/// \version 1.1
/// \date 2011
/////////////////////////////////////////////////////////////////////////////////// #ifndef _DATABASE_RECORD_SET_
#define _DATABASE_RECORD_SET_ #pragma comment(lib,"libmysql.lib")
#pragma warning(disable: 4786) ///<Disable warning messages #include <string>
#include <map> using namespace std; namespace Database
{
class CDBResultSet : public IDBResultSet
{
friend class CDBConnect; ///<友元类 private:
MYSQL_RES* m_pMyQuery; ///<结果集
MYSQL_ROW m_currentRow; ///<基类
unsigned int m_fieldCount; ///<字段的个数 private:
/////////////////////////////////////////////////////////////////////////////////
/// \brief CDBResultSet类的构造函数
/// \param[in] 无
/// \param[out] 无
/// \return 无
/////////////////////////////////////////////////////////////////////////////////
CDBResultSet(); /////////////////////////////////////////////////////////////////////////////////
/// \brief 释放结果集,得到字段的个数
/// \param[in] 结果集
/// \param[out] 无
/// \return 无
/////////////////////////////////////////////////////////////////////////////////
void Reset(MYSQL_RES *pMyQuery); public:
/////////////////////////////////////////////////////////////////////////////////
/// \brief CDBResultSet类的析构函数
/// \param[in] 结果集
/// \param[out] 无
/// \return 无
/////////////////////////////////////////////////////////////////////////////////
~CDBResultSet(){ Close(); } /////////////////////////////////////////////////////////////////////////////////
/// \brief 是否最后
/// \param[in] 无
/// \param[out] 无
/// \return TRUE 到最后 FALSE 没到最后
/////////////////////////////////////////////////////////////////////////////////
bool IsEnd(); /////////////////////////////////////////////////////////////////////////////////
/// \brief 查找指定数据
/// \param[in] 偏移量
/// \param[out] 无
/// \return 无
/////////////////////////////////////////////////////////////////////////////////
void SeekData(int offset); /////////////////////////////////////////////////////////////////////////////////
/// \brief 释放结果集
/// \param[in] 无
/// \param[out] 无
/// \return 无
/////////////////////////////////////////////////////////////////////////////////
void Close(); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到记录数
/// \param[in] 无
/// \param[out] 无
/// \return >=0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
DB_ROW_CONUT GetRowNum(); /////////////////////////////////////////////////////////////////////////////////
/// \brief 取得下一条记录
/// \param[in] 无
/// \param[out] 无
/// \return TRUE 正常 FALSE 异常
/////////////////////////////////////////////////////////////////////////////////
bool GetNextRecod(); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得有符号整型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, int& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得无符号整型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, unsigned int& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得字符串类型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, string& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得len长度的字符串值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, char* value, int len); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得bool值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, bool& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得float值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, float& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得double值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, double& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得时间类型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, time_t& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段,此函数分配内存,调用FreeGetFiledByte(BYTE **value)释放内存
/// \param[in] 字段下标
/// \param[out] 指向二进制buffer的指针
/// \param[out] 指针的长度
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(int filedId, uint8 **value, int *len); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得有符号整型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, int& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段下标
/// \param[out] 取得wu符号整型值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, unsigned int& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得字符串值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, string& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得len长度的字符串值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, char* value, int len); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得bool值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, bool& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得float值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, float& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段
/// \param[in] 字段名
/// \param[out] 取得double值
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, double& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段,此函数分配内存,调用FreeGetFiledByte(BYTE **value)释放内存
/// \param[in] 字段下标
/// \param[out] 指向二进制buffer的指针
/// \param[out] 指针的长度
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, time_t& value); /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段,此函数分配内存,调用FreeGetFiledByte(BYTE **value)释放内存
/// \param[in] 字段名
/// \param[out] 指向二进制buffer的指针
/// \param[out] 指针的长度
/// \return =0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiled(const char* fieldName, uint8 **value, int *len); private: /////////////////////////////////////////////////////////////////////////////////
/// \brief 得到字段ID
/// \param[in] 字段名
/// \param[out] 取得字段的ID
/// \return >=0 正常 <0异常
/////////////////////////////////////////////////////////////////////////////////
int GetFiedIdByName(const char* fieldName);
};
}
#endif

CPP文件: 

CDBResultSet::CDBResultSet()
{
m_pMyQuery = NULL;
m_currentRow = NULL;
m_fieldCount = 0;
} void CDBResultSet::Reset(MYSQL_RES *pMyQuery)
{
Close();
m_pMyQuery = pMyQuery;
m_currentRow = NULL;
if (pMyQuery != NULL)
{
m_fieldCount = mysql_num_fields(pMyQuery);
}
else
{
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "pMyQuery 未初始化\n");
}
m_fieldCount = 0;
}
} bool CDBResultSet::IsEnd()
{
if (m_pMyQuery == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMyQuery 未初始化\n");
}
return false;
}
return mysql_eof(m_pMyQuery) != 1;
} void CDBResultSet::SeekData(int offset)
{
if (m_pMyQuery == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMyQuery 未初始化\n");
}
return;
}
mysql_data_seek(m_pMyQuery, offset);
} void CDBResultSet::Close()
{
if (m_pMyQuery == NULL)
{
return;
}
mysql_free_result(m_pMyQuery);
m_pMyQuery = NULL;
m_currentRow = NULL;
m_fieldCount = 0;
} bool CDBResultSet::GetNextRecod()
{
if (m_pMyQuery == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMyQuery 未初始化\n");
}
return false;
}
if( (m_currentRow = mysql_fetch_row(m_pMyQuery)) != NULL)
{
return true;
}
else
{
if( NULL != pLC )
{
pLC->Warn( __FILE__, __LINE__, "m_currentRow 为空\n");
}
return false;
}
} DB_ROW_CONUT CDBResultSet::GetRowNum()
{
if (m_pMyQuery == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化\n");
}
return DATABASE_NOERROR;
}
return mysql_num_rows(m_pMyQuery);
} int CDBResultSet::GetFiled(int filedId, int& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
if (pField == NULL || pField[0] == 0)
{
value = 0;
return DATABASE_ERROR_NEXT_ROW;
}
value = atoi(pField);
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, unsigned int& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
if (pField == NULL || pField[0] == 0)
{
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "字段为空\n");
}
value = 0;
return DATABASE_ERROR_NEXT_ROW;
}
value = atoi(pField);
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, string& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
value = pField;
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, char* value, int len)
{
if (m_currentRow == NULL || filedId>=m_fieldCount || value == NULL || len < 0)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
if (m_currentRow[filedId] == NULL)
{
value[0] = '\0';
}
else
{
strncpy(value, m_currentRow[filedId], len-1);
value[len-1] = '\0';
}
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, bool& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
if (pField == NULL || pField[0] == 0)
{
if( NULL != pLC )
{
pLC->Warn( __FILE__, __LINE__, "字段为空\n");
}
value = false;
return DATABASE_ERROR_NEXT_ROW;
}
value = atoi(pField) != 0;
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, float& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
if (pField == NULL || pField[0] == 0)
{
if( NULL != pLC )
{
pLC->Warn( __FILE__, __LINE__, "字段为空\n");
}
value = 0.0;
return DATABASE_ERROR_NEXT_ROW;
}
value = atof(pField);
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, double& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
if (pField == NULL || pField[0] == 0)
{
if( NULL != pLC )
{
pLC->Warn( __FILE__, __LINE__, "字段为空\n");
}
value = 0.0;
return DATABASE_ERROR_NEXT_ROW;
}
value = atof(pField);
return DATABASE_NOERROR;
} int CDBResultSet::GetFiled(int filedId, time_t& value)
{
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
char* pField = m_currentRow[filedId];
tm time;
ZeroMemory(&time, sizeof(time));
if (pField == NULL || pField[0] == 0)
{
if( NULL != pLC )
{
pLC->Warn( __FILE__, __LINE__, "字段为空\n");
}
value = 0;
return DATABASE_ERROR_NEXT_ROW;
}
sscanf(pField, "%d-%d-%d %d:%d:%d", &time.tm_year, &time.tm_mon, &time.tm_mday, &time.tm_hour, &time.tm_min, &time.tm_sec);
time.tm_year -= 1900;
time.tm_mon -= 1;
value = mktime(&time);
return DATABASE_NOERROR;
} ///<函数功能:得到字段
int CDBResultSet::GetFiled(int filedId, uint8 **value, int *len)
{
*len = 0;
*value = NULL;
if (m_currentRow == NULL || filedId>=m_fieldCount)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_currentRow 未初始化或下标越界\n");
}
return DATABASE_ERROR_GET_FIELDS;
} if (m_currentRow[filedId] == NULL)
{
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "此字段为空\n");
*len = 0;
//*value = new uint8[1];
*value = (uint8 *)DATABASE_ALLOC(sizeof(uint8));
if (*value == NULL)
{
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "分配内存失败\n");
}
return DATABASE_ERROR_ALLOC_BUFFER;
}
(*value)[0] = '\0';
}
}
else
{ unsigned long * plLen = mysql_fetch_lengths(m_pMyQuery); //读该字段的长度,含0值数据
*len = (int)*plLen;
*value = (uint8 *)DATABASE_ALLOC(sizeof(uint8)*(*len) + 1);
if (*value == NULL)
{
*len = 0;
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "分配内存失败\n");
} return DATABASE_ERROR_ALLOC_BUFFER;
} for (int i = 0; i < *len; i++)
{
(*value)[i] = (uint8)m_currentRow[filedId][i];
} (*value)[*len] = '\0';
} return DATABASE_NOERROR;
} int CDBResultSet::GetFiedIdByName(const char* fieldName)
{
if (m_pMyQuery == NULL)
{
if( NULL != pLC )
{
pLC->Debug( __FILE__, __LINE__, "m_pMyQuery 未初始化\n");
}
return DATABASE_ERROR_GET_FIELDS;
}
for (int i=0; i<m_fieldCount; i++)
{
MYSQL_FIELD *pField = mysql_fetch_field_direct(m_pMyQuery, i);
if (pField != NULL && strcmp(pField->name, fieldName) == 0)
{
return i;
}
}
if( NULL != pLC )
{
pLC->Trace( __FILE__, __LINE__, "未找到该字段\n");
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, int& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, unsigned int& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, string& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, char* value, int len)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value, len);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, bool& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, float& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, double& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, time_t& value)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value);
} return DATABASE_ERROR_NEXT_ROW;
} int CDBResultSet::GetFiled(const char* fieldName, uint8 **value, int *len)
{
int id = 0;
if ((id=GetFiedIdByName(fieldName)) >= 0)
{
return GetFiled(id, value, len);
} return DATABASE_NOERROR;
}

【数据库开发】如何创建MySQL数据库连接池(一个基于libmysql的MySQL数据库连接池示例(C/C++版))的更多相关文章

  1. eShopOnContainers 是一个基于微服务的.NET Core示例框架

    找到一个好的示例框架很难,但不是不可能.大多数是小型Todo风格的应用程序,通常基于SimpleCRUD.值得庆幸的是,Microsoft已经为eShopOnContainers创建了一个基于微服务的 ...

  2. 【Android开发】创建你的第一个Android项目

    原文:http://android.eoe.cn/topic/summary 本文中你将了解到: 1. 使用Eclipse创建项目 2. 使用命令行创建项目 你还应该阅读: 1. 安装SDK(官网页面 ...

  3. Android TV开发总结(二)构建一个TV Metro界面(仿泰捷视频TV版)

    前言:上篇是介绍构建TV app前要知道的一些事儿,开发Android TV和手机本质上没有太大的区别,屏大,焦点处理,按键处理,是有别于有手机和Pad的实质区别.今天来介绍TV中Metro UI风格 ...

  4. 基于amoeba实现mysql数据库的读写分离/负载均衡

    一.Amoeba的简述:[来自百度百科]      Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy.它集中地响应应用的请求,依据用户事先设置的规则,将SQL请 ...

  5. Android TV开发总结(三)构建一个TV app的焦点控制及遇到的坑

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52835829 前言:上篇中,&l ...

  6. Java开发工程师(Web方向) - 03.数据库开发 - 第2章.数据库连接池

    第2章--数据库连接池 数据库连接池 一般而言,在实际开发中,往往不是直接使用JDBC访问后端数据库,而是使用数据库连接池的机制去管理数据库连接,来实现对后端数据库的访问. 建立Java应用程序到后端 ...

  7. 数据库连接池(基于MySQL数据库)

    使用JDBC是怎么保证数据库客户端和数据库服务端进行连接的? 通过代码: conn=DriverManager.getConnection(url, username, password); JDBC ...

  8. MYSQL 之 JDBC(十五):数据库连接池

    在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤: 在主程序(如servlet.bean)中建立数据库连接 进行sql操作 断开数据库连接 这种模式开发存在各种各样的问题,最重要的是:数 ...

  9. mysql数据库连接池使用(二)实现自己的数据库连接池

    上一个章节,我们讲了xml文件的解析框架XMLConfiguration的使用,不懂的可以参考 Apache Commons Configuration读取xml配置具体使用. 这个章节主要实现自己的 ...

随机推荐

  1. Define Interfaces and Share Class Members through Mixins in Dart

    In this lesson, we will cover Interfaces and Mixins. Interfaces act as a contract containing propert ...

  2. bzoj2738矩阵乘法

    题意: 给你一个N*N的矩阵,没有修改,每次询问一个子矩形中的第K小数. 题目链接 思路: 当它只有一列时,其实就是区间第K大,也就是整体二分可以解决的. 现在到了二维,只需要将之前的树状数组改成二维 ...

  3. All 关键字

    本文档已存档,并且将不进行维护. GROUP BY 子句和 ALL 关键字 SQL Server 2005 Transact-SQL 在 GROUP BY 子句中提供 ALL 关键字.只有在 SELE ...

  4. [TJOI2013]奖学金 乱搞

    [TJOI2013]奖学金 乱搞 从\(c\)个二元组\((v,w)\)中选出\(n\)个,使其\(v\)的中位数最大的同时使\(w\)和小于等于\(f\),求这个中位数 有点意思.有点像二分答案的思 ...

  5. P2543 [AHOI2004]奇怪的字符串

    题目描述 输入输出格式 输入格式: 输入文件中包含两个字符串X和Y.当中两字符串非0即1.序列长度均小于9999. 输出格式: X和Y的最长公共子序列长度. 输入输出样例 输入样例#1: 复制 010 ...

  6. Codeforces 221d D. Little Elephant and Array

    二次联通门 : Codeforces 221d D. Little Elephant and Array /* Codeforces 221d D. Little Elephant and Array ...

  7. ubuntu中防火墙iptables配置

    特别说明:此文章完全转载于https://www.cnblogs.com/EasonJim/p/6851007.html 1.查看系统是否安装防火墙 root@localhost:/usr# whic ...

  8. 微信小程序环境下将文件上传到 OSS

    步骤 1: 配置 Bucket 跨域 客户端进行表单直传到 OSS 时,会从浏览器向 OSS 发送带有 Origin 的请求消息.OSS 对带有 Origin 头的请求消息会进行跨域规则(CORS)的 ...

  9. python3实例

    1.一行代码求一个数的阶乘 例如:求5的阶乘 from functools import reduce print((lambda k: reduce(, k+), ))()) 借鉴:https:// ...

  10. Tcl模块化

    Proc 过程名 参数列表 过程体 示例代码(斐波那契数列): proc fib {num} { if {$num<=2} {return 1} return [expr [fib [expr ...