C++库(MySQL Connector)创建数据库连接池

一、MySql Connector简介

MySql Connector/C++8是一个用于连接MySQL服务器的C++应用程序。Connector/C++8可用于访问实现文档存储的 MySQL服务器,或者使用SQL查询以传统方式访问。它支持使用XDevAPI开发C ++应用程序,或使用XDevAPI for C开发纯C应用程序,同时Connector/C++8还支持与之前使用Connector/C++1.1中基于JDBC的旧API开发的C++应用程序一起编译及开发(即:向后兼容)。但是,Connector/C++8的首选开发环境是使用XDevAPI或XDevAPI for C。

二、下载MySql Connector
  1. 进入MySQL官方网站进行下载:MySQL Connector下载
    在这里插入图片描述
  2. 可以选择安装程序和下载压缩文件,本博客中下载的是压缩文件
    在这里插入图片描述
  3. 将下载好的压缩包进行解压缩,并将该问价夹下的所有文件添加到要使用的项目中
    在这里插入图片描述
三、连接池的介绍
1. 应用背景:
  1. 一般的应用程序都会访问到数据库,在程序访问数据库的时候,每一次数据访问请求都必须经过下面几个步骤:建立数据库连接,打开数据库,对数据库中的数据进行操作,关闭数据库连接。而建立数据库连接和打开数据库是一件很消耗资源并且费时的工作,如果在系统中很频繁的发生这种数据库连接,必然会影响到系统的性能,甚至会导致系统的崩溃。
2. 技术思想:
  1. 在系统初始化阶段,建立一定数量的数据库连接对象(Connection),并将其存储在连接池中定义的容器中。当有数据库访问请求时,就从连接池中的这个容器中拿出一个连接;当容器中的连接已经用完,并且还没有达到系统定义的最大连接数时,可以再创建一个新的连接,当当前使用的连接数达到最大连接数时,就要等待其他访问请求将连接放回容器后才能使用。当使用完连接的时候,必须将连接放回容器中,这样不同的数据库访问请求就可以共享这些连接,通过重复使用这些已经建立的数据库连接,可以解决上节中说到的频繁建立连接的缺点,从而提高了系统的性能。
    经过上述描述,我们可以归纳出数据库连接池的主要操作:
    (1)首先建立一个数据库连接池对象
    (2)初始化一定数量的数据库连接,放入连接池对象的容器中
    (3)当有数据库访问请求时,直接从连接池的容器中得到一个连接,这里出现三种情况:
    (a)当容器中的还有连接时,则返回给数据库访问请求者一个连接
    (b)当容器中没有连接时,并且当前建立的连接数没有达到系统定义的最大连接数,则创建一个新的数据库连接。
    (c)当容器中的没有连接并且当前建立的连接数达到系统定义的最大连接数,则当前访问数据库请求就要等待其他访问请求释放连接。
    (4)当数据库访问完成后,应该将连接放回连接池的容器中。
    (5)当服务停止时,需要先释放数据库连接池中的所有数据库连接,然后再释放数据库连接池对象。
四、使用该连接器实现MySql连接池
  1. 连接池实现的头文件
#pragma once
#include <mysqlconnector\mysql_connection.h>
#include <mysqlconnector\mysql_driver.h>
#include <condition_variable>

class CConnectPool
{
public:
	CConnectPool();
	~CConnectPool();

public:
	//创建一个连接,返回一个Connection
	sql::Connection * CreateConnection();
	//创建连接池实例
	static CConnectPool* GetInstance(const char *pUrl, const char *pDB, const char * pUserName, const char *pPwd);
	//设置连接池大小
	void SetPoolSize(int nMinSize, int nMaxSize);
	//初始化连接
	bool InitConnection();
	//在连接池中获得一个连接
	sql::Connection * GetConnection();
	//回收数据库连接
	void ReleaseConnection(sql::Connection *conn);
	//销毁连接池,首先要销毁连接池中的连接
	void DestroyPool();
	//销毁一个连接
	void DestroyConnection(sql::Connection *conn);
private:
	//连接池的构造函数
	CConnectPool(const char *pUrl, const char *pDB, const char * pUserName, const char *pPwd);
	

private:
	int m_nMinSize;
	int m_nMaxSize;

	std::string strUrl;
	std::string strUserName;
	std::string strPwd;
	std::string strDB;

	std::list<sql::Connection *> m_listConn;//连接池容器队列
	std::condition_variable m_variable;
	std::mutex m_mtx;

	static CConnectPool * pConnectPool;
	sql::Driver * driver;
};
  1. 连接池实现的源文件
#include <iostream>
#include "ConnectPool.h"

CConnectPool * CConnectPool::pConnectPool = nullptr;

CConnectPool::CConnectPool()
{
}

CConnectPool::~CConnectPool()
{
}

sql::Connection * CConnectPool::CreateConnection()
{
	sql::Connection *ptrConn = nullptr;
	try
	{
		//建立连接
		ptrConn = driver->connect(this->strUrl.c_str(), this->strUserName.c_str(), this->strPwd.c_str());
		return ptrConn;
	}
	catch (sql::SQLException& e)
	{
		std::cout << "创建mysql连接出错:" << e.what() << std::endl;
		return nullptr;
	}
	catch (std::runtime_error &e)
	{
		std::cout << "运行时出错:" << e.what() << std::endl;
		return nullptr;
	}
}

CConnectPool* CConnectPool::GetInstance(const char *pUrl, const char *pDB, const char * pUserName, const char *pPwd)
{
	if (nullptr == pConnectPool)
	{
		pConnectPool = new CConnectPool(pUrl,pDB,pUserName,pPwd);
	}
	return pConnectPool;
}

void CConnectPool::SetPoolSize(int nMinSize, int nMaxSize)
{
	m_nMaxSize = nMaxSize;
	m_nMinSize = nMinSize;
}

bool CConnectPool::InitConnection()
{
	sql::Connection *conn = nullptr;
	std::lock_guard<std::mutex> lock(m_mtx);
	size_t nSum = 0;
	size_t nCount = m_nMaxSize > m_nMinSize ? m_nMaxSize : m_nMinSize;
	for (size_t i = 0; i < nCount; ++i)
	{
		conn = this->CreateConnection();
		if (conn)
		{
			m_listConn.push_back(conn);
			nSum++;
		}
	}
	if (nSum < nCount)
	{
		return false;
	}
	return true;
}

sql::Connection * CConnectPool::GetConnection()
{
	sql::Connection *con = nullptr;
	std::lock_guard<std::mutex> lock(m_mtx);
	if (m_listConn.size() == 0)
	{
		return this->CreateConnection();
	}
	con = m_listConn.front();
	m_listConn.pop_front();

	if (!con->isClosed() && con->isValid())
	{
		return con;
	}
	else
	{
		return this->CreateConnection();
	}
}

void CConnectPool::ReleaseConnection(sql::Connection *conn)
{
	std::unique_lock<std::mutex> lock(m_mtx);
	if (conn)
	{
		m_listConn.push_back(conn);
		lock.unlock();
		m_variable.notify_one();
	}
}

void CConnectPool::DestroyPool()
{
	std::unique_lock<std::mutex> lock(m_mtx);
	for (auto it = m_listConn.begin(); it != m_listConn.end(); ++it)
	{
		//销毁连接池中的连接
		this->DestroyConnection(*it);
	}
	//清空连接池中的连接
	m_listConn.clear();
}

void CConnectPool::DestroyConnection(sql::Connection *conn)
{
	if (conn)
	{
		try
		{
			conn->close();
		}
		catch (sql::SQLException &e)
		{
			std::cout << "销毁一个连接错误:" << e.what() << std::endl;
		}
		catch (std::exception &e)
		{
			std::cout << e.what() << std::endl;
		}
		delete conn;
		conn = nullptr;
	}
}

CConnectPool::CConnectPool(const char *pUrl, const char *pDB, const char * pUserName, const char *pPwd)
{
	this->strUrl = pUrl;
	this->strDB = pDB;
	this->strUserName = pUserName;
	this->strPwd = pPwd;
	try
	{
		//获取mysql数据库驱动
		this->driver = sql::mysql::get_driver_instance();
	}
	catch (sql::SQLException& e)
	{
		std::cout << "mysql驱动连接出错:" << e.what() << std::endl;
		//可由自己的日志模块进行输出
	}
	catch (std::runtime_error& e)
	{
		std::cout << "mysql运行出错:" << e.what() << std::endl;
	}

	if (!this->InitConnection())
	{
		std::cout << "初始化连接池出错" << std::endl;
	}
}
  1. 数据库管理的头文件
#pragma once
#include "ConnectPool.h"
#include <mysqlconnector\cppconn\resultset.h>
#include <mysqlconnector\cppconn\statement.h>
#include <vector>

class CMysqlDataBase
{
public:
	CMysqlDataBase();
	~CMysqlDataBase();

public:
	static void CreateDataBase();
	//登录数据库
	virtual bool Login(int nMinPoolSize, int nMaxPoolSize);
	//登出数据库
	virtual void Logout();
	//操作数据库
	virtual bool RunSqlExec(const std::string & strsql);
	virtual sql::ResultSet *RunSqlQuery(const std::string strsql);
	virtual bool RunSqlExecTrans(const std::vector<std::string>& vecstrsql);
	//设置数据库信息
	virtual void SetDbSvrInfo(const char* pHost, unsigned short nHostPort, const char* pDbName);
	//设置用户登录信息
	virtual void SetUserLogInfo(const char* pUserName, const char* pPwd);

public:
	static CMysqlDataBase *m_pMysql;

private:
	CConnectPool *m_pConnPool;

	std::string m_strDbName;
	std::string m_strHostIp;
	unsigned short m_nPort;
	std::string m_strUserName;
	std::string m_strPwd;
};
  1. 数据库管理的源文件
#include "MysqlDataBase.h"
#include <sstream>

CMysqlDataBase *CMysqlDataBase::m_pMysql = nullptr;

CMysqlDataBase::CMysqlDataBase()
{
}

CMysqlDataBase::~CMysqlDataBase()
{
}
void CMysqlDataBase::CreateDataBase()
{
	if (nullptr == m_pMysql)
	{
		m_pMysql = new CMysqlDataBase();
	}
}

bool CMysqlDataBase::Login(int nMinPoolSize, int nMaxPoolSize)
{
	std::stringstream ss;
	ss << "tcp://" << m_strHostIp << ":" << m_nPort << "/" << m_strDbName;

	std::string strUrl = ss.str();

	m_pConnPool = CConnectPool::GetInstance(strUrl.c_str(), m_strDbName.c_str(), m_strUserName.c_str(), m_strPwd.c_str());
	if (!m_pConnPool)
	{
		std::cout << "获取连接池实例失败" << std::endl;
		return false;
	}

	m_pConnPool->SetPoolSize(nMinPoolSize, nMaxPoolSize);
	
	bool bResult = m_pConnPool->InitConnection();
	if (bResult)
	{
		//初始化成功
		//启动消息队列
	}
	else
		return false;
	return bResult;
}
void CMysqlDataBase::Logout()
{
	m_pConnPool->DestroyPool();
}

bool CMysqlDataBase::RunSqlExec(const std::string & strsql)
{
	sql::Connection *pConn = m_pConnPool->GetConnection();
	if (!pConn)
	{
		std::cout << "运行时获取连接失败" << std::endl;
		return false;
	}
	sql::Statement *state = pConn->createStatement();
	//true:sql命令的提交(commit)由驱动程序负责
	//false:sql命令的提交由应用程序负责,程序必须调用commit或者rollback方法
	pConn->setAutoCommit(false);
	try
	{
		state->execute("set character set gbk;");
		///ddl存储过程中有返回是否成功的结果集,不能用 executupdate
		state->execute(strsql.c_str());
		do
		{
			state->getResultSet();
		} while (state->getMoreResults());

		pConn->commit();
		pConn->setAutoCommit(true);
		state->close();
		delete state;
	}
	catch (sql::SQLException& e)
	{
		delete state;
		m_pConnPool->ReleaseConnection(pConn);
		std::cout << "Exec执行失败" << std::endl;
		return false;
	}
	catch (const std::exception&)
	{
		delete state;
		m_pConnPool->ReleaseConnection(pConn);
		std::cout << "Exec执行失败" << std::endl;
		return false;
	}
	m_pConnPool->ReleaseConnection(pConn);
	return true;
}

sql::ResultSet *CMysqlDataBase::RunSqlQuery(const std::string strsql)
{
	sql::Connection *pConn = m_pConnPool->GetConnection();
	if (!pConn)
	{
		std::cout << "获取连接失败" << std::endl;
		return nullptr;
	}

	sql::Statement *state = pConn->createStatement();
	sql::ResultSet *result = nullptr;

	try
	{
		state->execute("set character set gbk;");
		result = state->executeQuery(strsql.c_str());	//用来查询数据库信息
		do
		{
			state->getResultSet();
		} while (state->getMoreResults());
		state->close();
		delete state;
	}
	catch (sql::SQLException& e)
	{
		delete state;
		m_pConnPool->ReleaseConnection(pConn);
		std::cout << "查询数据库失败:" << e.what() << std::endl;
		return nullptr;
	}
	catch (const std::exception& e)
	{
		delete state;
		m_pConnPool->ReleaseConnection(pConn);
		std::cout << "查询数据库失败:" << e.what() << std::endl;
		return nullptr;
	}

	m_pConnPool->ReleaseConnection(pConn);
	return result;
}

bool CMysqlDataBase::RunSqlExecTrans(const std::vector<std::string>& vecstrsql)
{
	sql::Connection *pConn = m_pConnPool->GetConnection();
	if (!pConn)
	{
		std::cout << "获取数据库连接失败" << std::endl;
		return false;
	}
	sql::Statement *state = pConn->createStatement();
	pConn->setAutoCommit(false);
	state->execute("set character set gbk;");
	for (const auto &str : vecstrsql)
	{
		try
		{
			state->execute(str.c_str());
			do
			{
				state->getResultSet();
			} while (state->getMoreResults());
		}
		catch (sql::SQLException& e)
		{
			std::cout << "ExecTrans执行失败:" << e.what() << std::endl;
		}
		catch (const std::exception& e)
		{
			std::cout << "ExecTrans执行失败:" << e.what() << std::endl;
		}
	}
	pConn->commit();
	pConn->setAutoCommit(true);
	state->close();
	delete state;
	m_pConnPool->ReleaseConnection(pConn);
	return true;
}
void CMysqlDataBase::SetDbSvrInfo(const char* pHost, unsigned short nHostPort, const char* pDbName)
{
	m_strHostIp = pHost;
	m_nPort = nHostPort;
	m_strDbName = pDbName;
}
void CMysqlDataBase::SetUserLogInfo(const char* pUserName, const char* pPwd)
{
	m_strUserName = pUserName;
	m_strPwd = pPwd;
}

猜你喜欢

转载自blog.csdn.net/weixin_38739598/article/details/106924638