2021-07-30

如何用C++自己实现mysql数据库的连接池?

为什么是mysql?

现在几乎所有的后台应用都要用到数据库,什么关系型的、非关系型的;正当关系的,不正当关系的;主流的和非主流的, 大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网的时序数据库,比如涛思的TDengine,咱们中国人自己的开源时序数据库,性能杠杠滴。

凡此总总,即使没用过,也听说过,但大部分人或企业用的最多的就是白嫖型数据库:mysql。该数据库的特点就是无论是个人还是企业都能玩的起。像Oracle这种名媛型数据库基本就属于银行特供,银行需要花钱买平安,心里踏实。不买对的,只选贵的,因为人家确实不差钱。

如果你的后台应用连数据库都不需要,那跟咸鱼网站有什么区别呢?就是咸鱼二手网也要用到数据库的。如果一个IT民工一辈子没用过数据库就在35(~45)岁时"被退休",那他的职业生涯是遗憾的,是不完美的,是不纯粹的。 好歹年轻是也要用一下非主流的Access吧,哪怕Execel也成。这种感觉就好比在大学时没谈过恋爱一样,光忙着羡慕别人就突然毕业了。

为什么要搞资源池?

目前大部分后台程序都选择Java开发或PHP,这两种语言的第三方库非常丰富,丰富到让开发人员的只要将精力放在具体业务上即可。比如数据库的资源池,只要选择好适当的jar包外加配置好相应的数据库参数,即可放心大胆的使用mysql。

当然,如果你命硬的话,也可以选择用C或C++开发后台应用。这时候你就需要自己DIY一个数据库资源池。

如果只是一个客户端程序,基本不需要连接池,但对于后台应用来说,高并发就意味着多线程,多线程程就意味着资源的竞争。内存访问如此,数据库访问也是如此。每次数据库的打开和关闭就是一次网络连接和关闭的过程,频繁的打开和关闭无疑会浪费大量的系统资源。这时候就需要提前建立好N个连接,并放在资源池中并提供给不同线程访问使用。

mysql资源池实现的案例源码

我一直相信好的代码是不需要过的语言来解释的,代码即文档,要啥自行车。以下案例只是一个实现思路,供参考。

头文件:MysqlPool.h

#pragma warning(disable : 4786)	#include <windows.h>#include <winsock2.h>#include <mysql.h>					// 确保你的机器有mysql开发库#include <vector>#include <string>using namespace std;#define DEFAULT_POOL_SIZE		20	// 缺省mysql连接池中的数量#define DEFAULT_POOL_TIMEOUT	60	// 获取池中mysql连接的超时// 自定义数据库查询回调函数typedef BOOL (CALLBACK *LPFN_RetrieveRecordData)(MYSQL_ROW& sqlRow, MYSQL_FIELD* pSqlFields, int iFieldCount, DWORD dwUserData);// Mysql数据库连接类class CMysqlConn{public:	CMysqlConn(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 				const char* pszDBUser, const char* pszDBPwd);	virtual ~CMysqlConn();	public:	// 打开/关闭一个mysql连接	BOOL Open();	void Close();		// ping连接是否已关闭	BOOL Ping();	// 重置字符集	BOOL ResetCharset();		public:	// ================SQL语句操作(简单实现几个)================	// 查询	BOOL	Select(const char* pszSql, LPFN_RetrieveRecordData lpfnRetrieveRecordData, DWORD dwUserData);	// 执行	BOOL	Execute(const char* pszSql);	// 插入,如果主键是自增整型,返回插入后的主键值	__int64 Insert(const char* pszSql);		protected:	MYSQL*	m_pMysql;			// mysql数据库操作对象	// 以下是连接mysql需要的参数	string	m_strDBServer;		// mysql数据库所在服务器	UINT	m_uDBPort;			// mysql数据库连接端口	string	m_strDBName;		// 数据库名称	string	m_strDBUser;		// 数据库账户	string	m_strDBPwd;			// 数据库密码	};// 数据库连接池实现class CMysqlPool {public:	CMysqlPool();	virtual ~CMysqlPool();	// 创建mysql连接池	BOOL Create(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 				const char* pszDBUser, const char* pszDBPwd,	 			DWORD dwPoolSize = DEFAULT_POOL_SIZE, 				DWORD dwTimeOut = DEFAULT_POOL_TIMEOUT);				// 销毁连接池 	void Destroy(); 	public:	// 获取一个mysql连接 	CMysqlConn* Get();	// 释放一个mysql连接 	void Release(CMysqlConn* pConn);	protected:	HANDLE				m_hSemaphore;  // 信号量句柄	DWORD				m_dwPoolSize;		// 连接池大小 	DWORD				m_dwTimeOut;		// 超时,单位秒	CRITICAL_SECTION	m_csPool;			// 连接池锁	vector<CMysqlConn*>	m_vecIdle;			// 闲队列	vector<CMysqlConn*>	m_vecBusy;			// 忙队列};

实现文件:MysqlPool.cpp

#include "stdafx.h"#include "MysqlPool.h"#include <assert.h>#include <algorithm>#pragma comment(lib, "libmysql.lib")	//连接MysQL需要的库//////////////////////////////////////////////////////////////////////// CMysqlConn: mysql数据库连接类//////////////////////////////////////////////////////////////////////CMysqlConn::CMysqlConn(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 						const char* pszDBUser, const char* pszDBPwd){	assert(pszDBServer);	assert(pszDBName);	assert(pszDBUser);	assert(pszDBPwd);	m_pMysql = NULL;	m_strDBServer = pszDBServer;	m_uDBPort = uDBPort;	m_strDBName = pszDBName;	m_strDBUser = pszDBUser;	m_strDBPwd = pszDBPwd;}CMysqlConn::~CMysqlConn(){	Close();}// 打开一个mysql数据库,即建立一个数据库连接BOOL CMysqlConn::Open(){	if(m_pMysql)	{		mysql_close(m_pMysql);	// 关闭连接			m_pMysql = NULL;	}		m_pMysql = mysql_init(NULL);	if(!m_pMysql)		return FALSE;		// 连接数据库 if(!mysql_real_connect(m_pMysql, m_strDBServer.c_str(), m_strDBUser.c_str(),							m_strDBPwd.c_str(), m_strDBName.c_str(), m_uDBPort, NULL, 0)) {		int i = mysql_errno(m_pMysql);		const char * pszErr = mysql_error(m_pMysql);		return FALSE;	}		// 设置重连	char chValue = 1;	mysql_options(m_pMysql, MYSQL_OPT_RECONNECT, &chValue);		mysql_query(m_pMysql,"set names 'gbk'"); 		return TRUE;}// 关闭数据库连接void CMysqlConn::Close(){	if(m_pMysql)		mysql_close(m_pMysql);	// 断开连接	m_pMysql = NULL;	}// ping一下mysql,看看连接还活着BOOL CMysqlConn::Ping(){	if(m_pMysql)		return (0 == mysql_ping(m_pMysql));	return FALSE;}// 设置字符集为GBKBOOL CMysqlConn::ResetCharset(){	if(m_pMysql)		return (0 == mysql_query(m_pMysql, "set names 'gbk'")); 	return FALSE;}// mysql执行:delete 或 updateBOOL CMysqlConn::Execute(const char* pszSql){	assert(pszSql);	if(!m_pMysql)		return FALSE;		MYSQL_STMT *myStmt = mysql_stmt_init(m_pMysql);	if(!myStmt)	{		return FALSE;	}		if(0 != mysql_stmt_prepare(myStmt, pszSql, strlen(pszSql)))	{		mysql_stmt_close(myStmt);		return FALSE;	}	if(0 != mysql_stmt_execute(myStmt))	{		mysql_stmt_close(myStmt);		return FALSE;	}	mysql_stmt_close(myStmt);		return TRUE;		}// mysql插入__int64 CMysqlConn::Insert(const char* pszSql){		assert(pszSql);	MYSQL_STMT *myStmt = mysql_stmt_init(m_pMysql);	if(!myStmt)		return 0;		if(0 != mysql_stmt_prepare(myStmt, pszSql, strlen(pszSql)))	{		int i = mysql_errno(m_pMysql);		const char * s = mysql_error(m_pMysql);		mysql_stmt_close(myStmt);		return 0;	}	if(0 != mysql_stmt_execute(myStmt))	{		mysql_stmt_close(myStmt);		return 0;	}	mysql_stmt_close(myStmt);		__int64 i64ID = mysql_insert_id(m_pMysql);		return i64ID;}// mysql查询BOOL CMysqlConn::Select(const char* pszSql, LPFN_RetrieveRecordData lpfnRetrieveRecordData, DWORD dwUserData){	if(!m_pMysql)		return FALSE;		if(NULL == lpfnRetrieveRecordData)		return FALSE;		if(0 != mysql_real_query(m_pMysql, pszSql, strlen(pszSql)))	{		return FALSE;		}		MYSQL_RES *resRecord = mysql_store_result(m_pMysql);	int iFieldCount = resRecord->field_count;		MYSQL_ROW sqlRow;	while (sqlRow = mysql_fetch_row(resRecord)) {		if(!lpfnRetrieveRecordData(sqlRow, resRecord->fields, iFieldCount, dwUserData))			break;	}	mysql_free_result(resRecord);	return TRUE;}//////////////////////////////////////////////////////////////////////// CMysqlPool: mysql数据库连接池类//////////////////////////////////////////////////////////////////////CMysqlPool::CMysqlPool(){	::InitializeCriticalSection(&m_csPool);}CMysqlPool::~CMysqlPool(){	Destroy();	::DeleteCriticalSection(&m_csPool);}// 创建mysql连接池BOOL CMysqlPool::Create(const char* pszDBServer, UINT uDBPort, const char* pszDBName, 						const char* pszDBUser, const char* pszDBPwd,						DWORD dwPoolSize, DWORD dwTimeOut){	m_dwTimeOut = dwTimeOut;	m_dwPoolSize = dwPoolSize;		// 创建信号量	m_hSemaphore = ::CreateSemaphore(NULL, dwPoolSize, dwPoolSize, NULL);	if (NULL == m_hSemaphore)	{		return FALSE;	}		// 创建数据库连接池	for(DWORD i = 0; i < dwPoolSize; ++i)	{		// 创建一个mysql数据库连接		CMysqlConn *pConn = new CMysqlConn(pszDBServer, uDBPort, pszDBName, pszDBUser, pszDBPwd);		if(!pConn->Open())			{			delete pConn;			continue;		}		m_vecIdle.push_back(pConn);	}	return m_vecIdle.size() > 0;	}// 销毁mysql连接池void CMysqlPool::Destroy(){	::CloseHandle(m_hSemaphore);	m_......

原文转载:http://www.shaoqun.com/a/894420.html

跨境电商:https://www.ikjzd.com/

声网agora:https://www.ikjzd.com/w/2176

zappos.com:https://www.ikjzd.com/w/330

扬帆计划:https://www.ikjzd.com/w/1581


为什么是mysql?现在几乎所有的后台应用都要用到数据库,什么关系型的、非关系型的;正当关系的,不正当关系的;主流的和非主流的,大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网的时序数据库,比如涛思的TDengine,咱们中国人自己的开源时序数据库,性能杠杠滴。凡此总总,即使没用过,也听说过,但大部分人或企业用的最多的就是白嫖型数据库:mysql。该数据库的特点就是无论是个人还
泰山最佳旅游时间攻略:http://www.30bags.com/a/418380.html
泰山最佳旅游时间是什么时候:http://www.30bags.com/a/418332.html
泰式按摩怎么回事?有什么效果啊?:http://www.30bags.com/a/405525.html
泰新马旅游一般安排几天比较合适?:http://www.30bags.com/a/405503.html
口述实录:我和父亲那难以启齿的秘密:http://lady.shaoqun.com/a/71480.html
口述:我意乱情迷爱上老妈的闺蜜老妈闺蜜儿子:http://lady.shaoqun.com/m/a/43131.html
强壮的公么征服我厨房 我在洗碗他在下面弄我:http://www.30bags.com/m/a/249935.html
校花好紧太爽再快点 把校花的腿扛在肩上疯狂输出:http://www.30bags.com/m/a/249881.html
爱情故事:美女面具(爱情短篇):http://lady.shaoqun.com/a/428568.html
2021广东旅游年卡价格多少钱:http://www.30bags.com/a/519700.html
亚马逊攻略!想爆单?用这4招轻松赢得buy box:https://www.ikjzd.com/articles/147065
过去一年,亚马逊中东站有哪些进展?:https://www.ikjzd.com/articles/147060

No comments:

Post a Comment