如何创建数据库连接池(一个基于libmysql的MySQL数据库连接池示例)
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命令: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;}
5、 总结
总结就不必了,本文出自个人本科毕设摘抄整理,未经允许不得转载,如需转载请联系horace20@live.cn,如若学校说我论文是抄别人的,那我就冤枉了……