对于连接的管理可使用空闲池。即把已经创建但尚未分配出去的连接按创建时间存放到一个空闲池中。每当用户请求一个连接时,系统首先检查空闲池内有没有空闲连接。如果有就把建立时间最长(通过容器的顺序存放实现)的那个连接分配给他(实际是先做连接是否有效的判断,如果可用就分配给用户,如不可用就把这个连接从空闲池删掉,重新检测空闲池是否还有连接);如果没有则检查当前所开连接池是否达到连接池所允许的最大连接数(maxConn),如果没有达到,就新建一个连接,如果已经达到,就等待一定的时间(timeout)。如果在等待的时间内有连接被释放出来就可以把这个连接分配给等待的用户,如果等待时间超过预定时间timeout,则返回空值(null)。系统对已经分配出去正在使用的连接只做计数,当使用完后再返还给空闲池。对于空闲连接的状态,可开辟专门的线程定时检测,这样会花费一定的系统开销,但可以保证较快的响应速度。也可采取不开辟专门线程,只是在分配前检测的方法。
连接池的实现
1、连接池模型
本文讨论的连接池包括一个连接池类(DBConnectionPool)和一个连接池管理类(DBConnetionPoolManager)。连接池类是对某一数据库所有连接的“缓冲池”,主要实现以下功能:①从连接池获取或创建可用连接;②使用完毕之后,把连接返还给连接池;③在系统关闭前,断开所有连接并释放连接占用的系统资源;④还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。
连接池管理类是连接池类的外覆类(wrapper),符合单例模式,即系统中只能有一个连接池管理类的实例。其主要用于对多个连接池对象的管理,具有以下功能:①装载并注册特定数据库的JDBC驱动程序;②根据属性文件给定的信息,创建连接池对象;③为方便管理多个连接池对象,为每一个连接池对象取一个名字,实现连接池名字与其实例之间的映射;④跟踪客户使用连接情况,以便需要是关闭连接释放资源。连接池管理类的引入主要是为了方便对多个连接池的使用和管理,如系统需要连接不同的数据库,或连接相同的数据库但由于安全性问题,需要不同的用户使用不同的名称和密码。
2、连接池实现
class CManageConnection
{
private:
float m_CreateTime;
ConnectionPtr m_conn;
Bool m_IsConnection;
public:
CManageConnection(float intime,Cstring strConn);
~ CManageConnection();
Bool IsConnection(); //是否空闲
Bool IsFreeConnection();//是否还是可用连接
ConnectionPtr GetConnection();
Private:
RealseConn();
}
class CmanagePoolConn
{
private:
int minConn;//连接池里连接的最小数量
int maxConn;//连接池里允许存在的最大连接数
int checkedOut;//已被分配出去的连接数
Cstring m_strConn;//连接字符串
Timer timer;//定时器
CArray< CManageConnection *, CManageConnection *> m_A ManageConn;
Public :
CmanagePoolConn();
~ CmanagePoolConn();
public:
void CreateManagePool(int innum1,int innum2,Cstring instr);
void FreeManagePool();
_ConntionPtr * GetConnection ();
private :
void TimerEvent() //定时器事件处理函数
CManageConnection *NewManageConnection();//新建一个连接
Void DelectOldConnection(int index);//删除无用连接
}
二,一个数据库连接池实现
// ConnObject.h: interface for the CConnObject class.
//
//
#if !defined(AFX_CONNOBJECT_H__2818382C_8737_44D0_B319_1032C614EFEE__INCLUDED_)
#define AFX_CONNOBJECT_H__2818382C_8737_44D0_B319_1032C614EFEE__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "Database.h"
class CConnPool;
class CConnObject
{
public:
CConnObject(CConnPool * pool)
{
ASSERT(pool);
pPool = pool;
// conn = NULL;
m_bInUse = FALSE;
m_nLastEnd = 0;
m_nLastBegin = 0;
m_nUseCount = 0;
m_nTotalUseTime = 0;
}
~CConnObject();
// 用完本身不能关闭,交给连接池处理
public:
//释放连接对象给连接池
void Close();
Database conn;
BOOL m_bInUse;
int m_nLastEnd; //最后一次使用结束时间
int m_nLastBegin; //最后一次开始时间
int m_nUseCount; //使用次数
CConnPool * pPool;
int m_nTotalUseTime;
public:
//得到总得使用时间
int GetTotalUseTime()
{
return m_nTotalUseTime;
}
};
CConnObject::~CConnObject()
{
}
void CConnObject::Close()
{
m_nTotalUseTime += GetTickCount() - m_nLastBegin;
pPool->Close(this);
}
#endif //
// ConnPool.h: interface for the CConnPool class.
//
//
#if !defined(AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_)
#define AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <atlbase.h>
#include "ConnObject.h"
/***************************************
数据库连接池.
一个连接池对应于一个库
****************************************/
/*
*/
class CConnPool
{
public:
void OnTimer();
static void __stdcall TimerProc(HWND hWnd, UINT msg, UINT id, DWORD dwTime);
//得到一个连接
CConnObject * GetConnect();
//释放一个连接回连接池
void Close(CConnObject * pConn);
//销毁连接池
void Destroy();
//创建连接池 strConn: 连接串
BOOL Init(CString strConn);
CConnPool();
virtual ~CConnPool();
public:
UINT m_nTimer; //定时器
CSimpleArray<CConnObject *> m_listConn; //连接链表
UINT m_nTimeOut; //连接最大空闲时间
UINT m_ConnMax; //连接数量上限
UINT m_ConnMin; //连接数量下限
UINT m_nMaxCount; //连接最大使用次数
UINT m_nMaxUseTime; //最大使用时间
CString m_strConn; //连接串
HANDLE m_cs; //保证改变连接池状态时代码不终端
protected:
//创建一个新的连接
CConnObject * CreateNewConn();
};
#endif // !defined(AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_)
// ConnPool.cpp: implementation of the CConnPool class.
//
//
#include "stdafx.h"
#include "HTRDServer.h"
#include "ConnPool.h"
#include "const_def.h"
#include "MyEvent.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
CConnPool::CConnPool()
{
m_ConnMin = CONN_MIN;
m_nTimeOut = CONN_TIMEOUT;
m_nMaxUseTime = CONN_MAX_USETIME;
m_nMaxCount = 500;
m_cs = CreateEvent(NULL, TRUE, TRUE, "da8b4c9d-e4ef-4c9a-a6d2-941ee98400d2");
}
CConnPool::~CConnPool()
{
Destroy();
}
BOOL CConnPool::Init(CString strConn)
{
m_ConnMax = theApp.m_sysSetting.m_nConnCount;
m_strConn = strConn;
for (UINT i = 0;i < m_ConnMax; i++)
{
CConnObject * pObj = CreateNewConn();
if (!pObj)
return FALSE;
m_listConn.Add(pObj);
}
return TRUE;
//启动连接池维护计时器
// m_nTimer = SetTimer(0, 0, CONNPOOL_TIMER, (TIMERPROC)TimerProc);
}
void CConnPool::Destroy()
{
for (int i = 0;i < m_listConn.GetSize(); i++)
{
m_listConn[i]->m_bInUse = FALSE;
m_listConn[i]->conn.Close();
// m_listConn[i]->conn->Release();
delete m_listConn[i];
}
m_listConn.RemoveAll();
KillTimer(NULL, m_nTimer);
}
/*
* 释放连接时需要保护数据一致性,所以使用 临界对象
*/
void CConnPool::Close(CConnObject *pConn)
{
//回收!
CMyEvent cs(m_cs);
for (int i = 0;i < m_listConn.GetSize(); i++)
{
if (m_listConn[i] == pConn)
{
m_listConn[i]->m_bInUse = FALSE;
m_listConn[i]->m_nUseCount++;
m_listConn[i]->m_nLastEnd = ::GetTickCount();
//判断使用次数是否过多,使用时间是否过多
//如果过度使用该连接,则重新创建
if (m_listConn[i]->m_nUseCount > (int)m_nMaxCount ||
m_listConn[i]->GetTotalUseTime() > CONN_MAX_USETIME)
{
OUTPUT_MSG("有数据库连接对象使用过多,需要重新连接/r/n");
m_listConn[i]->conn.Close();
if (!m_listConn[i]->conn.Open("", "", m_strConn.GetBuffer(0)))
{
AfxMessageBox("重新数据库连接对象出错!, 系统退出!");
ExitProcess(0);
}
m_listConn[i]->m_nLastBegin = 0;
m_listConn[i]->m_nLastEnd = 0;
m_listConn[i]->m_nTotalUseTime = 0;
m_listConn[i]->m_nUseCount = 0;
}
return;
}
}
#ifdef _DEBUG
AfxMessageBox("The connect object is no mine!");
#endif
}
/*
* 得到连接时需要保护数据一致性,所以使用 临界对象
*/
CConnObject * CConnPool::GetConnect()
{
CMyEvent cs(m_cs);
CConnObject * pObj = NULL;
for (int i = 0;i < m_listConn.GetSize(); i++)
{
if (!m_listConn[i]->m_bInUse)
{
m_listConn[i]->m_bInUse = TRUE;
pObj = m_listConn[i];
pObj->m_nLastBegin = ::GetTickCount();
return pObj;
}
}
if ((pObj == NULL) &&
(m_listConn.GetSize() < (int)m_ConnMax)) //connect object is no enough!
{
pObj = CreateNewConn();
pObj->m_bInUse = TRUE;
m_listConn.Add(pObj);
return pObj;
}
//连接池已经满载!
return NULL;
}
CConnObject * CConnPool::CreateNewConn()
{
CConnObject * pConn = new CConnObject(this);
if (!pConn->conn.Open("","",_bstr_t(m_strConn)))
return NULL;
return pConn;
}
void CConnPool::TimerProc(HWND hWnd, UINT msg, UINT id, DWORD dwTime)
{
// CHTRDServerApp * pApp = (CHTRDServerApp *)AfxGetApp();
// ASSERT(pPool);
// pPool->OnTimer();
}
/*
* 调度连接池
*/
void CConnPool::OnTimer()
{
DWORD dwTime = ::GetTickCount();
for (int i = 0; i < m_listConn.GetSize(); i++)
{
if (m_listConn[i]->conn.m_Cnn->State == adStateClosed)
{
//delete from pool
delete m_listConn[i];
m_listConn.RemoveAt(i);
TRACE("One conn closed!, delete from pool!/n");
}
else if (!m_listConn[i]->m_bInUse)
{
if (dwTime - m_listConn[i]->m_nLastEnd >= m_nTimeOut)
{
m_listConn[i]->conn.Close();
delete m_listConn[i];
m_listConn.RemoveAt(i);
TRACE("One conn time out!/n");
}
else if (m_listConn[i]->m_nUseCount >= (int)m_nMaxCount)
{
m_listConn[i]->conn.Close();
delete m_listConn[i];
m_listConn.RemoveAt(i);
TRACE("One conn use to much!/n");
}
}
else if (m_listConn[i]->GetTotalUseTime() >= (int)m_nMaxUseTime)
{
m_listConn[i]->conn.Close();
delete m_listConn[i];
m_listConn.RemoveAt(i);
TRACE("One conn use too long/n");
}
}
//检查连接数,小于下限则添加到下限
for (i = m_listConn.GetSize(); i < (int)m_ConnMin;i++)
{
CConnObject * pObj = CreateNewConn();
ASSERT(pObj);
m_listConn.Add(pObj);
}
}
三,在LINUX下用C/C++写了一个连接池(访问MYSQL)的类
一、头文件【存为:connPool.h】
#ifndef __CONNECTION_POOL_H__
#define __CONNECTION_POOL_H__
#include "mutex.h"
#define
using namespace std;
enum _USE_STATUS
{
};
typedef
{
}sConStatus;
class CConnPool
{
public:
public:
public:
public:
};
class CConnPoolV2
{
public:
public:
private:
private:
};
#endif
二、源码【存为:connPool.cpp】
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <time.h>
#include <iostream>
#include <memory>
#include <string>
#include <map>
#include <vector>
#include "mysql.h"
#include "encapsulation_mysql.h"
#include "connPool.h"
#include "mutex.h"
using namespace std;
using namespace EncapMysql;
CConnPool::CConnPool( )
{
}
CConnPool::~CConnPool( )
{
}
void* CConnPool::createOneConn()
{
}
int CConnPool::Init(string& strMysqlIp, string&
{
}
//从连接池中取一个连接,同时,给它做一个标记,表明它已经被使用,防止别的线程再使用。
void* CConnPool::getOneConn()
{
}
//把连接归还给连接池。同时,给它做一个标记,表明它是空闲的,可以使用。
void
{
}
void
{
}
// 2011-01-20, 这个类这样写,感觉耦合性更为松散,比较好。使用起来也好理解一些。
CConnPoolV2::CConnPoolV2( )
{
}
CConnPoolV2::~CConnPoolV2( )
{
}
//创建一个连接,并设为 IDLE状态。
void* CConnPoolV2::createOneConn()
{
}
//成功: 返回0
int CConnPoolV2::Init(string& strMysqlIp, string&
{
}
void* CConnPoolV2::getOneConn()
{
}
void
{
}
void
{
}