C++ 结合mysql-connector 的连接池实验记录

网上学习时找到了这篇数据库连接池文章 http://blog.csdn.net/cscmaker/article/details/6679256 点击打开链接

所以直接对这篇文章进行了一次实验.实验环境:

vs2012 

mysql-connector-c++-noinstall-1.1.9-win32


整个工程就主要包含三部分

(1)头文件部分:

connection_pool.h

#ifndef _CONNECTION_POOL_H  
#define _CONNECTION_POOL_H  
#include<mysql_connection.h>  
#include<mysql_driver.h>  
#include<cppconn/exception.h>  
#include<cppconn/driver.h>  
#include<cppconn/connection.h>  
#include<cppconn/resultset.h>  
#include<cppconn/prepared_statement.h>  
#include<cppconn/statement.h>
#include<list>  

#include "Lock.h" 
#pragma  comment(lib,"mysqlcppconn.lib")
using namespace std;  
using namespace sql;

class ConnPool{ 
public:  
	ConnPool(string url,string user,string password,int maxSize);//构造方法  
	~ConnPool();
private:  
	int curSize;//当前已建立的数据库连接数量  
	int maxSize;//连接池中定义的最大数据库连接数  
	string username;  
	string password;  
	string url;  
	list<Connection*>connList;//连接池的容器队列

	//创建一个互斥对象 
	Mutex g_Lock;  
	static ConnPool *connPool;  
	Driver*driver;  

	void InitConnection(int iInitialSize);//初始化数据库连接池 
	Connection *CreateConnection();//创建一个连接  	 
	void DestoryConnection(Connection *conn);//销毁数据库连接对象  
	void DestoryConnPool();//销毁数据库连接池  
	
 
public:
	static ConnPool *GetInstance();//获取数据库连接池单例对象 
	Connection*GetConnection();//获得数据库连接  
	void ReleaseConnection(Connection *conn);//将数据库连接放回到连接池的容器中  
	 
};



#endif 

str.h  [ 因为在调用MySQL的命令时,字符串命令的输入会特定的要求比如UTF8等等 ]

//主要用作字符来回转换

#ifndef __STR_HH
#define __STR_HH


#include<string>
#include<windows.h>
#include<vector>
inline static std::string UnicodeToUtf8(const wchar_t* buf)
{
	int len = ::WideCharToMultiByte(CP_UTF8, 0, buf, -1, NULL, 0, NULL, NULL);
	if (len == 0) return "";

	std::vector<char> utf8(len);
	::WideCharToMultiByte(CP_UTF8, 0, buf, -1, &utf8[0], len, NULL, NULL);

	return &utf8[0];
}

inline static std::wstring AnsiToUnicode(const char* buf)
{
	int len = ::MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0);
	if (len == 0) return L"";

	std::vector<wchar_t> unicode(len);
	::MultiByteToWideChar(CP_ACP, 0, buf, -1, &unicode[0], len);

	return &unicode[0];
}

#endif //__STR_HH

Lock.h  [这是为了之后的线程操作之间的互斥]
#ifndef _Lock_H
#define _Lock_H 

#include <windows.h> 

//锁接口类 
class IMyLock
{ 
public:
	virtual~IMyLock() {} 

	virtual void Lock() const= 0; 
	virtual void Unlock() const= 0; 
};  

//互斥对象锁类 
class Mutex :public IMyLock
{ 
public:
	Mutex();
	~Mutex(); 

	virtual void Lock() const;
	virtual void Unlock() const; 

private:
	HANDLE m_mutex;
};  

//锁 
class CLock
{ 
public:
	CLock(const IMyLock&);
	~CLock(); 

private:
	const IMyLock& m_lock;
}; 


//自己模仿写了封装一个使用Mutex的锁类
class MyTestLock
{
public:
	MyTestLock();
	~MyTestLock();
	void DoLock();//上锁
	void UnLocked();//解锁

private:
	HANDLE h_mutex;
};


#endif 

(2)主函数部分
#include "connection_pool.h"
#include "str.h"


//初始化連接池
ConnPool *connpool = ConnPool::GetInstance();

MyTestLock* pLock;

LRESULT StartThread(void*pParam) 
{
	//char*pMsg = (char*)pParam;
	DWORD* num=(DWORD*)pParam;
	Connection *con;
	Statement *state;
	ResultSet *result;

	// 從連接池中獲取mysql連接【里面有锁,为了排队有序的去取】
	con = connpool->GetConnection();

	state = con->createStatement();
	//state->execute("use holy");指定要访问的某一特定数据库

	pLock->DoLock();

	//1.查詢数据库中现有记录条数
	result = state->executeQuery("SELECT * FROM monitor_device");
	cout<<num<<" 号线程查询统计: "<<result->rowsCount()<<endl;

	//2.自己项数据库中插入1条记录

	//先检测字段是否已经存在,不存在就添加
	string sqlStr="SELECT id FROM monitor_device WHERE name='玲珑居'";
	wstring strUnicode=AnsiToUnicode(sqlStr.c_str());
	string strUtf8 = UnicodeToUtf8(strUnicode.c_str());

	result = state->executeQuery(strUtf8.c_str());
	int ret=result ->rowsCount();
	if(ret<1)
	{//没有在数据库中找到该条记录,添加
		string  pSQLComLine="INSERT INTO monitor_device VALUES (null, null, null, null, null, '0', '14', '1', '1', '1111111111111111111111111', 'admin', '北京', 'D', '37777', 'admin', '3', null, '1');";
		strUnicode=AnsiToUnicode(pSQLComLine.c_str());
		strUtf8 = UnicodeToUtf8(strUnicode.c_str());
		BOOL Bret=state->execute(strUtf8.c_str());
		con -> commit();
		if(!Bret)
		{
			if(state->getUpdateCount()>0)
				cout<<num<<" 号线程插入记录成功"<<endl<<endl;
		}

		delete state;state=NULL;
		connpool->ReleaseConnection(con);
	}

	else
	{
		cout<<num<<" 号线程检查记录已经存在不继续添加了"<<endl<<endl;
		delete state;state=NULL;
		connpool->ReleaseConnection(con);
	}


	pLock->UnLocked();
	return 0;
}


int main(int argc,char* argv[])
{ 
	pLock=new MyTestLock();

	//HANDLE hThread1, hThread2;
	//unsigned int uiThreadId1, uiThreadId2; 
	//char*pMsg1 ="First print thread.";
	//char*pMsg2 ="Second print thread."; 
	创建两个工作线程,分别打印不同的消息
	//hThread1 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg1, 0, (LPDWORD)&uiThreadId1);
	//hThread2 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg2, 0, (LPDWORD)&uiThreadId2); 
	hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void*)pMsg1, 0, &uiThreadId1); 
	hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void*)pMsg2, 0, &uiThreadId2);  
	等待线程结束
	//DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
	//if( dwRet == WAIT_TIMEOUT )
	//{
	//	TerminateThread(hThread1,0);
	//}
	//dwRet = WaitForSingleObject(hThread2,INFINITE);
	//if( dwRet == WAIT_TIMEOUT )
	//{
	//	TerminateThread(hThread2,0);
	//}
	关闭线程句柄,释放资源
	//::CloseHandle(hThread1);
	//::CloseHandle(hThread2);


	HANDLE ThredHandle[5];
	DWORD ThreadID[5];
	for(int i=0;i<5;i++){
		ThredHandle[i]=::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)i, 0, (LPDWORD)&ThreadID[i]);
	}
	WaitForMultipleObjects(5,ThredHandle,TRUE,INFINITE);
	for(int i=0;i<5;i++){
		::CloseHandle(ThredHandle[i]);
	}



	delete pLock;pLock=NULL;
	system("pause");
	return 0;
}

(3)对应的cpp部分

connection_pool.cpp
#include<stdexcept>  
#include<exception>  
#include<stdio.h>  
#include"connection_pool.h"

//创建一个连接池对象指针 
ConnPool* ConnPool::connPool=NULL;


ConnPool* ConnPool::GetInstance()
{
	if(connPool==NULL)  
	{  
		connPool=new ConnPool("tcp://localhost:3306/monitor_device","root","cdx",10);  
	}  
	return connPool; 
}

ConnPool::ConnPool(string url,string user,string password,int maxSize)
{
	this->url=url;
	this->username=user;
	this->password=password;  
	this->maxSize=maxSize;  
	this->curSize=0; 

	try{  
		this->driver=sql::mysql::get_driver_instance();  
	}  
	catch(sql::SQLException&e)  
	{  
		perror("驱动连接出错;\n");  
	}  
	catch(std::runtime_error&e)  
	{  
		perror("运行出错了\n");  
	}

	this->InitConnection(maxSize/2); 

}

//初始化连接池,创建最大连接数的一半连接数量  
void ConnPool::InitConnection(int iInitialSize)
{
	Connection* conn;  
	//pthread_mutex_lock(&lock); 

	for(int i=0;i<iInitialSize;i++)  
	{  
		conn=this->CreateConnection();  
		if(conn){  
			connList.push_back(conn);  
			++(this->curSize);  
		}  
		else  
		{  
			perror("创建CONNECTION出错");  
		}  
	}  

	//pthread_mutex_unlock(&lock);  
}

//创建连接,返回一个Connection 
sql::Connection * ConnPool::CreateConnection()
{
	Connection* conn;  
	try{  
		conn=driver->connect(this->url.c_str(),this->username.c_str(),this->password.c_str());//建立连接  
		return conn;  
	}  
	catch(sql::SQLException&e)  
	{  
		perror("创建连接出错");  
		return NULL;  
	}  
	catch(std::runtime_error&e)  
	{  
		perror("运行时出错");  
		return NULL;  
	}  

}

//在连接池中获得一个连接  
Connection*ConnPool::GetConnection(){  
	Connection*con;  
	
	// 新建对象时自动加锁
	//函数结束前,对象析构时自动解锁
	CLock Temlock(g_Lock);//pthread_mutex_lock(&lock); 

	if(connList.size()>0)//连接池容器中还有连接  
	{  
		con=connList.front();//得到第一个连接  
		connList.pop_front();//移除第一个连接  
		if(con->isClosed())//如果连接已经被关闭,删除后重新建立一个  
		{  
			delete con;  
			con=this->CreateConnection();  
		}  
		//如果连接为空,则创建连接出错  
		if(con==NULL)  
		{  
			--curSize;  
		}  
		//pthread_mutex_unlock(&lock);  
		return con;  
	}  
	else
	{  
		if(curSize< maxSize)
		{//还可以创建新的连接  
			con= this->CreateConnection();  
			if(con){  
				++curSize;  
				//pthread_mutex_unlock(&lock);  
				return con;  
			}  
			else{  
				//pthread_mutex_unlock(&lock);  
				return NULL;  
			}  
		}  
		else{//建立的连接数已经达到maxSize  
			//pthread_mutex_unlock(&lock);  
			return NULL;  
		}  
	}  
}  

//回收数据库连接  
void ConnPool::ReleaseConnection(sql::Connection * conn){  
	if(conn){  
		CLock Temlock(g_Lock);//pthread_mutex_lock(&lock);  
		connList.push_back(conn);  
		//pthread_mutex_unlock(&lock);  
	}  
}  

//连接池的析构函数  
ConnPool::~ConnPool()  
{  
	this->DestoryConnPool();  
}  
//销毁连接池,首先要先销毁连接池的中连接  
void ConnPool::DestoryConnPool(){  
	list<Connection*>::iterator icon;

	CLock Temlock(g_Lock);//pthread_mutex_lock(&lock);

	for(icon=connList.begin();icon!=connList.end();++icon)  
	{  
		this->DestoryConnection(*icon);//销毁连接池中的连接  
	}  
	curSize=0;  
	connList.clear();//清空连接池中的连接 

	//pthread_mutex_unlock(&lock);  
}  

//销毁一个连接  
void ConnPool::DestoryConnection(Connection* conn)  
{  
	if(conn)  
	{  
		try{  
			conn->close();  
		}  
		catch(sql::SQLException&e)  
		{  
			perror(e.what());  
		}  
		catch(std::exception&e)  
		{  
			perror(e.what());  
		}  
		delete conn;  
	}  
}  

Lock.cpp
#include "Lock.h" 

//创建一个匿名互斥对象 
Mutex::Mutex() 
{ 
	m_mutex = ::CreateMutex(NULL, FALSE, NULL);
} 

//销毁互斥对象,释放资源 
Mutex::~Mutex() 
{ 
	::CloseHandle(m_mutex);
}  

//确保拥有互斥对象的线程对被保护资源的独自访问
void Mutex::Lock()const
{ 
	DWORD d = WaitForSingleObject(m_mutex, INFINITE);
}  

//释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问
void Mutex::Unlock()const
{ 
	::ReleaseMutex(m_mutex);
}  




//利用C++特性,进行自动加锁
CLock::CLock(const IMyLock& m) : m_lock(m)
{ 
	m_lock.Lock();
}  

//利用C++特性,进行自动解锁
CLock::~CLock() 
{ 
	m_lock.Unlock();
} 



//互斥作用步骤

//锁住一个互斥器(Mutex)

//欲获得一个mutex的拥有权,请使用Win32的Wait...()函数。Wait...()对mutex所做的事情和EnterCriticalSection()对critical section所做的事情差不多,倒是一大堆术语容易让人迷惑。
	//一旦没有任何线程拥有mutex,这个mutex便处于激发状态,因此,如果没有任何线程拥有那个mutex,Wait...()便会成功。
	//反过来说,当线程拥有mutex时,它处于未被激发状态,如果有某个线程正在等待一个未被激发的mutex,它便将进入“blocking”(阻塞)状态。也就是说,该线程会停止执行,直到mutex被其拥有者释放并处于激发状态。

//下面是某种情节的流程:
	//1.我们有一个mutex,此时没有任何线程拥有它;
	//2.某个线程调用WaitForSingleObject()(或任何其他的Wait...()函数,并指定该mutex handle为参数;
	//3.Win32于是将该mutex的拥有权给予这个线程,然后将此mutex的状态短暂地设为激发状态,于是Wait...()函数返回。
	//4.Mutex立刻又被设定为非激发状态,使任何处于等待下的其他线程没有办法获得其拥有权。
	//5.获得该mutex之线程调用ReleaseMutex(),将mutex释放掉。
   //于是循环回到第1场景,周而复始。


MyTestLock::MyTestLock()
{
	h_mutex = ::CreateMutex(NULL, FALSE, NULL);
}

MyTestLock::~MyTestLock()
{
	::CloseHandle(h_mutex);
}

void MyTestLock::DoLock()
{
	WaitForSingleObject(h_mutex, INFINITE);
}

void MyTestLock::UnLocked()
{
	::ReleaseMutex(h_mutex);
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值