项目场景:
单例模式,并能正确地析构。智能指针的使用。
connection_pool.h
/*
*File: connection_pool.h
*Author: fengwei
*/
#ifndef _CONNECTION_POOL_H
#define _CONNECTION_POOL_H
#include <mysql/jdbc.h>
#include <windows.h>
#include <list>
#include <iostream>
using namespace std;
using namespace sql;
/*通过写一个加锁的类来对共享的数据进行有效的安全控制,防止内存错误*/
class MTCMutex
{
public:
MTCMutex() :_mutex(NULL)
{
this->_mutex = CreateMutex(NULL, FALSE, NULL);
if (this->_mutex == NULL)
throw std::exception("CreateMutex 失败!");
}
virtual ~MTCMutex()
{
if (this->_mutex)
{
CloseHandle(this->_mutex);
std::cout << "mutex" << std::endl;
this->_mutex = NULL;
}
}
MTCMutex(const MTCMutex& mutex) { *this = mutex; }
MTCMutex& operator=(const MTCMutex& other)
{
if (this != &other)
{
this->_mutex = other._mutex;
}
return *this;
}
private:
HANDLE _mutex;
public:
BOOL Lock()
{
DWORD dwRet = ::WaitForSingleObject(this->_mutex, INFINITE);
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED)
return TRUE;
else
return FALSE;
}
void UnLock()
{
ReleaseMutex(this->_mutex);
}
};
class ConnPool {
private:
int curSize; //当前已建立的数据库连接数量
int maxSize; //连接池中定义的最大数据库连接数
string username;
string password;
string url;
list<Connection*> connList; //连接池的容器队列 STL list 双向链表
static MTCMutex lock; //线程锁
static ConnPool *connPool;
Driver*driver;
Connection*CreateConnection(); //创建一个连接
void InitConnection(int iInitialSize); //初始化数据库连接池
void DestoryConnection(Connection *conn); //销毁数据库连接对象
void DestoryConnPool(); //销毁数据库连接池
ConnPool(string url, string user, string password, int maxSize); //构造方法
class GGarbo
{
public:
~GGarbo()
{
if (connPool != NULL)
{
std::cout << "~GGarbo()" << std::endl;
delete connPool;
connPool = NULL;
}
}
};
static GGarbo bo;
public:
~ConnPool();
Connection*GetConnection(); //获得数据库连接
void ReleaseConnection(Connection *conn); //将数据库连接放回到连接池的容器中
static ConnPool *GetInstance(); //获取数据库连接池对象
};
#endif /*_CONNECTION_POOL_H */
connection_pool.cpp
#include <stdexcept>
#include <exception>
#include <stdio.h>
#include "connection_pool.h"
using namespace std;
using namespace sql;
ConnPool* ConnPool::connPool = NULL;
MTCMutex ConnPool::lock;
ConnPool::GGarbo ConnPool::bo;
// 获取连接池对象,单例模式
ConnPool* ConnPool::GetInstance()
{
if (connPool == NULL)
{
ConnPool::lock.Lock();
if (connPool == NULL)
connPool = new ConnPool("localhost", "root", "123456", 50);
ConnPool::lock.UnLock();
}
return connPool;
}
// 数据库连接池的构造函数
ConnPool::ConnPool(string url, string userName, string password, int maxSize)
{
this->maxSize = maxSize;
this->curSize = 0;
this->username = userName;
this->password = password;
this->url = url;
try
{
this->driver = sql::mysql::get_driver_instance();
}
catch (sql::SQLException& e)
{
perror(e.what());
}
catch (std::runtime_error& e)
{
perror(e.what());
}
// 在初始化连接池时,建立一定数量的数据库连接
this->InitConnection(maxSize / 2);
}
// 初始化数据库连接池,创建最大连接数一半的连接数量
void ConnPool::InitConnection(int iInitialSize)
{
Connection* conn;
ConnPool::lock.Lock();
for (int i = 0; i < iInitialSize; i++)
{
conn = this->CreateConnection();
if (conn)
{
connList.push_back(conn);
++(this->curSize);
}
else
{
throw std::exception("Init connection error.");
}
}
ConnPool::lock.UnLock();
}
// 创建并返回一个连接
Connection* ConnPool::CreateConnection()
{
Connection* conn;
try
{
sql::ConnectOptionsMap connection_properties;
connection_properties[OPT_HOSTNAME] = this->url;
connection_properties[OPT_USERNAME] = this->username;
connection_properties[OPT_PASSWORD] = this->password;
connection_properties[OPT_CHARSET_NAME] = sql::SQLString("gbk");
connection_properties[OPT_CHARACTER_SET_RESULTS] = sql::SQLString("gbk");
// 建立连接
conn = driver->connect(connection_properties);
return conn;
}
catch (sql::SQLException& e)
{
perror(e.what());
return NULL;
}
catch (std::runtime_error& e)
{
perror(e.what());
return NULL;
}
}
// 从连接池中获得一个连接
Connection* ConnPool::GetConnection()
{
Connection* con;
ConnPool::lock.Lock();
// 连接池容器中还有连接
if (connList.size() > 0)
{
// 获取第一个连接
con = connList.front();
// 移除第一个连接
connList.pop_front();
// 判断获取到的连接的可用性
// 如果连接已经被关闭,删除后重新建立一个
if (con->isClosed())
{
delete con;
con = this->CreateConnection();
// 如果连接为空,说明创建连接出错
if (con == NULL)
{
// 从容器中去掉这个空连接
--curSize;
}
}
ConnPool::lock.UnLock();
return con;
}
// 连接池容器中没有连接
else
{
// 当前已创建的连接数小于最大连接数,则创建新的连接
if (curSize < maxSize)
{
con = this->CreateConnection();
if (con)
{
++curSize;
ConnPool::lock.UnLock();
return con;
}
else
{
ConnPool::lock.UnLock();
return NULL;
}
}
// 当前建立的连接数已经达到最大连接数
else
{
perror("[GetConnection] connections reach the max number.");
ConnPool::lock.UnLock();
return NULL;
}
}
}
// 释放数据库连接,将该连接放回到连接池中
void ConnPool::ReleaseConnection(sql::Connection* conn)
{
static int i= 0;
if (conn)
{
ConnPool::lock.Lock();
i++;
std::cout << "ReleaseConnection次数" << i << std::endl;
connList.push_back(conn);
ConnPool::lock.UnLock();
}
}
// 数据库连接池的析构函数
ConnPool::~ConnPool()
{
this->DestoryConnPool();
}
// 销毁连接池,需要先销毁连接池的中连接
void ConnPool::DestoryConnPool()
{
list<Connection*>::iterator itCon;
ConnPool::lock.Lock();
for (itCon = connList.begin(); itCon != connList.end(); ++itCon)
{
// 销毁连接池中的连接
this->DestoryConnection(*itCon);
}
curSize = 0;
// 清空连接池中的连接
connList.clear();
ConnPool::lock.UnLock();
}
// 销毁数据库连接
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;
}
}
DWORD WINAPI Fun(LPVOID lp)
{
std::unique_ptr < Connection, function<void(Connection *)>> con(ConnPool::GetInstance()->GetConnection(), [](Connection *c)->void
{
ConnPool::GetInstance()->ReleaseConnection(c);
}
);
for (int i = 0; i < 20; i++)
{
std::unique_ptr< Statement> state(con->createStatement());
//state = con->createStatement();
state->execute("use test");
Sleep(500);
// 查询数据库
std::unique_ptr<ResultSet> result(state->executeQuery("SELECT * from student"));
// 打印数据库查询结果
cout << "================================" << endl;
while (result->next())
{
int nRoleId = result->getInt(1);
string strOccupation = result->getString(2);
string strCamp = result->getString(4);
cout <<"当前线程是"<<GetCurrentThreadId()<<":"<< nRoleId << " , " << strOccupation << " , " << strCamp << endl;
}
cout << "i is: " << i << endl;
cout << "================================" << endl;
}
return EXIT_SUCCESS;
}
单例实现:
ConnPool* ConnPool::GetInstance()
{
//方法一
/*if (connPool == NULL)
{
ConnPool::lock.Lock();
if (connPool == NULL)
connPool = new ConnPool("localhost", "root", "123456", 30,3);
ConnPool::lock.UnLock();
}*/
//方法二
/*static std::once_flag s_flag;
std::call_once(s_flag, [&]() {
connPool = new ConnPool("localhost", "root", "123456", 30, 3);
});*/
//方法三
static INIT_ONCE InitOnce = INIT_ONCE_STATIC_INIT;
InitOnceExecuteOnce(&InitOnce, [](PINIT_ONCE InitOnce, PVOID Parameter, PVOID *context)->BOOL
{
connPool = new ConnPool("localhost", "root", "123456", 30, 3);
return TRUE;
},
nullptr, nullptr
);
return connPool;
}