网上学习时找到了这篇数据库连接池文章 http://blog.youkuaiyun.com/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);
}