一种利用ADO连接池操作MySQL的解决方案(VC++)
VC++连接MySQL数据库 常用的方式有三种:ADO、mysql++,mysql API ; 本文只讲述ADO的连接方式。
为什么要使用连接池? 对于简单的数据库应用,完全可以先创建一个常连接(此连接永远不关闭,直接数进程退出),但是这样做至少会引起两个问题:(1)资源竞争,多个数据库请求操作不能同时进行,后一请求必须要等到前一请求完成后才能进行;(2)多线程情况下容易出现混乱,甚至出现资源异常释放。还有一种方法,就是使用数据库时创建连接,使用完后关闭连接回收资源。这种方式在数据库操作频繁的情况下会出现严重的效率问题。
数据库连接池
百度百科给出的解释说明如下:
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
使用数据库连接池至少带来以下几个好处:
1、资源复用
数据库连接得到复用,避免了频繁创建、释放引起的系统性能开销。减少了内存碎片以及数据库线程(甚至是进程)的数量。
2、提高系统响应速度
由于数据库连接资源得到复用,这毫无疑问会提高系统的整体响应速度。
3、避免资源泄漏
所有的连接都集中在连接池中统一管理,这可以避免使用单一连接带来的两个问题。
实现原理
一个较为完备的数据库连接池应具备以下几个条件:
(1)实始化时创建一定数据量的连接对象放于连接池中。
(2)连接池对象要有上限。
(3)连接使用完毕后要放回连接池而不是直接释放掉。
(4)长期处于空闲态的连接要释放。
最为完整的实现原理请参考百度百科:数据库连接池。
下面给出一个简单的ADO数据库连接池实现代码:
(说明:以下代码没有考虑到上述原理的第(4)点,读者请根据自身需要自行实现之。)
//==================头文件 =====================//
//定义数据库连结基本信息结构
typedef struct
{
char db_ip[]; //ip地址
uint32 db_port; //端口
char db_user[];//用户
char db_pwd[];//密码
char db_dbname[];//数据库名
}vos_dbxmlinfo_stru; class CXCADOPOOL
{
protected:
CXCADOPOOL(); public:
virtual ~CXCADOPOOL(void); //接口
public:
void InitConnection(const int iMin, const int iMax);
bool ExcuteSql(_bstr_t bSql, bool bCheck = true);
bool GetRecordSet(_bstr_t bSql, _RecordsetPtr& pRecord, long lOption = adCmdText, bool bCheck = true); bool GetItemValue(_RecordsetPtr pRecord, long nIndex, int& nValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, UINT64& unValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, string& strValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, double& fValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, float& fValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, ULONG & nValue); bool GetItemValue(_RecordsetPtr pRecord, long nIndex, short& nValue);
bool GetItemValue(_RecordsetPtr pRecord, long nIndex, unsigned char& nValue);
bool GetItemValue(_RecordsetPtr pRecord, string fieldname, string& strValue); template<class T>
bool GetItemValue(_RecordsetPtr pRecord, string fieldname, T& tValue); static CXCADOPOOL *Instance();
_ConnectionPtr *GetTransConnection();
void SendTransCompMsg(_ConnectionPtr *pConptr);
bool ExecuteTransSql(_ConnectionPtr *pConptr, _bstr_t bSql);
private:
bool CreateDBConnection(_ConnectionPtr & conptr); //返回一个连接
void GetConnectionString(string &strConnect);
_ConnectionPtr * GetConnectionPtr();
void ReleaseConnectionPtr(_ConnectionPtr &conptr);
void InitDBConfig();
bool ExcuteWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql);
bool GetRecordSetWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql, _RecordsetPtr& pRecord, long lOption = adCmdText);
static DWORD WINAPI IdleConnThreadFunc(LPVOID lParam);
private: queue<_ConnectionPtr *> m_qConn;
int m_MinConNum; //最小连接数
int m_MaxConNum; //最大连接数
int m_CurrentNum; //当前连接数 HANDLE m_Mutex;
HANDLE m_hEvent;
HANDLE m_hThread;
DWORD m_dwThreadId;
HANDLE m_hThreadEvent;
string m_strConnect;
static CXCADOPOOL* _instance;
public:
vos_dbxmlinfo_stru m_stDBInfo; }; template<class T>
bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, string fieldname, T& tValue)
{
try
{
ASSERT_RECORDSET(pRecord);
_variant_t vart = pRecord->GetCollect(_variant_t(fieldname.c_str()));
(tValue = (T)(vart));
}
catch (_com_error &)
{
return false;
}
return true;
}
extern CXCADOPOOL *pAdoPool;
//===================.CPP文件=====================// bool CXCADOPOOL::GetItemValue( _RecordsetPtr pRecord, long nIndex, int& nValue )
{
try
{
ASSERT_RECORDSET(pRecord); nValue = (int)(pRecord->GetFields()->GetItem(nIndex)->Value);
}
catch (_com_error &)
{
return false;
}
return true;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, UINT64& unValue)
{
try
{
ASSERT_RECORDSET(pRecord); unValue = (UINT64)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
}
return true;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, ULONG& nValue)
{ try
{
ASSERT_RECORDSET(pRecord); nValue = (ULONG)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
}
return true; }
bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, string& strValue)
{
try
{
ASSERT_RECORDSET(pRecord); _variant_t vart = pRecord->GetFields()->GetItem(nIndex)->Value;
if (vart.vt == VT_NULL)
return true; strValue = (std::string)(bstr_t)vart;
}
catch (_com_error &)
{
return false;
} return true;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, double& fValue)
{
try
{
ASSERT_RECORDSET(pRecord); fValue = (double)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
} return true; } bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, float& fValue)
{
try
{
ASSERT_RECORDSET(pRecord); fValue = (float)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
}
return true;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, short &sValue)
{
try
{
ASSERT_RECORDSET(pRecord);
sValue = (short)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
}
return true;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, unsigned char& cValue)
{
try
{
ASSERT_RECORDSET(pRecord);
cValue = (unsigned char)pRecord->GetFields()->GetItem(nIndex)->Value;
}
catch (_com_error &)
{
return false;
}
return true;
} CXCADOPOOL *pAdoPool = NULL; CXCADOPOOL *CXCADOPOOL::_instance = NULL; CXCADOPOOL::CXCADOPOOL()
{ ::CoInitialize(NULL); InitDBConfig();
GetConnectionString(m_strConnect);
m_Mutex = ::CreateMutex(NULL, FALSE, NULL);
m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
m_CurrentNum = ; m_hThreadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = ::CreateThread(NULL, ,(LPTHREAD_START_ROUTINE)IdleConnThreadFunc, this, , &m_dwThreadId);
WaitForSingleObject(m_hThreadEvent, INFINITE);
CloseHandle(m_hThreadEvent); } CXCADOPOOL::~CXCADOPOOL(void)
{
::CoUninitialize();
} void CXCADOPOOL::InitConnection(const int iMin, const int iMax)
{
static bool bInitial = true;
if (bInitial)
{
m_MinConNum = iMin;
m_MaxConNum = iMax;
for (int i = ; i < iMin; i++)
{
_ConnectionPtr *conptr = new _ConnectionPtr;
if (CreateDBConnection(*conptr))
{
WaitForSingleObject(m_Mutex,INFINITE);
m_qConn.push(conptr);
m_CurrentNum++;
ReleaseMutex(m_Mutex);
}
}
bInitial = false;
}
} bool CXCADOPOOL::CreateDBConnection(_ConnectionPtr & conptr)
{
try
{
//conptr.CreateInstance("ADODB.Connection");
conptr.CreateInstance(__uuidof(Connection)); HRESULT hr = conptr->Open(m_strConnect.c_str(), "", "", adModeUnknown);
if (FAILED(hr))
{
return false;
}
}
catch (_com_error &e)
{
return false;
}
return true;
} void CXCADOPOOL::GetConnectionString(string &strConnect)
{
USES_CONVERSION;
CString str;
str.Format(_T("Driver=MySQL ODBC 5.3 Unicode Driver;SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;PORT=%d"),
A2T((char*)m_stDBInfo.db_ip), A2T((char*)m_stDBInfo.db_user), A2T((char*)m_stDBInfo.db_pwd), A2T((char*)m_stDBInfo.db_dbname), m_stDBInfo.db_port);
strConnect = T2A(str); } void CXCADOPOOL::InitDBConfig()
{
GetPrivateProfileStringA("DBInfo", "host", "localhost", m_stDBInfo.db_ip, , ".\\DB.ini");
m_stDBInfo.db_port = GetPrivateProfileIntA("DBInfo", "port", , ".\\DB.ini");
GetPrivateProfileStringA("DBInfo", "dbname", "", m_stDBInfo.db_dbname, , ".\\DB.ini");
GetPrivateProfileStringA("DBInfo", "user", "", m_stDBInfo.db_user, , ".\\DB.ini"); char pbuf_text[] = { };
GetPrivateProfileStringA("DBInfo", "password", "", pbuf_text, , ".\\DB.ini");
} bool CXCADOPOOL::ExcuteSql(_bstr_t bSql, bool bCheck)
{ _ConnectionPtr *conptr = GetConnectionPtr();
bool bExec = ExcuteWithoutCheck(*conptr, bSql);
PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)conptr,NULL);
return bExec;
} _ConnectionPtr * CXCADOPOOL::GetConnectionPtr()
{
//找出空闲连接
while ()
{
WaitForSingleObject(m_Mutex, INFINITE);
_ConnectionPtr *conptr;
if (m_qConn.empty())
{
if (m_CurrentNum < m_MaxConNum)
{
conptr = new _ConnectionPtr;
if (CreateDBConnection(*conptr))
{
m_CurrentNum++;
}
}
else
{
//等待连接释放
ResetEvent(m_hEvent);
ReleaseMutex(m_Mutex);
WaitForSingleObject(m_hEvent, INFINITE);
continue;
}
}
else
{
conptr = m_qConn.front();
m_qConn.pop();
} ReleaseMutex(m_Mutex);
return conptr;
} } DWORD WINAPI CXCADOPOOL::IdleConnThreadFunc(LPVOID lParam)
{
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
CXCADOPOOL *pCXCADOPOOL = static_cast<CXCADOPOOL *>(lParam);
SetEvent(pCXCADOPOOL->m_hThreadEvent); while ()
{
if (GetMessage(&msg, , , ))
{
switch (msg.message)
{
case WM_USER_DB_THREAD_MSG:
{
_ConnectionPtr *conptr = (_ConnectionPtr *) (msg.wParam); WaitForSingleObject(pCXCADOPOOL->m_Mutex,INFINITE);
pCXCADOPOOL->m_qConn.push(conptr);
ReleaseMutex(pCXCADOPOOL->m_Mutex);
SetEvent(pCXCADOPOOL->m_hEvent); }
default:
break;
}
}
}
return ;
} void CXCADOPOOL::ReleaseConnectionPtr(_ConnectionPtr &conptr)
{
if (conptr != NULL)
{
conptr->Close(); //关闭连接
conptr.Release(); //释放内存
conptr = NULL; } } bool CXCADOPOOL::ExcuteWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql)
{
int i = ;
while (i < )
{
try
{
if ( != i)
{
ReleaseConnectionPtr(conptr);
CreateDBConnection(conptr);
}
++i;
VARIANT nRecordAffected = { };
conptr->Execute(bSql, &nRecordAffected, adCmdText);
//ReleaseMutex(m_Mutex); if (nRecordAffected.date < )
{
return false;
}
break;
}
catch (_com_error&e)
{
}
catch (...)
{ }
}
if (i == )
{
return false;
} return true;
} bool CXCADOPOOL::GetRecordSet(_bstr_t bSql, _RecordsetPtr& pRecord, long lOption /*= adCmdText*/, bool bCheck)
{ _ConnectionPtr *conptr = GetConnectionPtr();
bool bExec = GetRecordSetWithoutCheck(*conptr, bSql, pRecord,lOption);
PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)conptr, NULL);
return bExec;
} bool CXCADOPOOL::GetRecordSetWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql, _RecordsetPtr& pRecord, long lOption /*= adCmdText*/)
{
for (int i = ; i < ; ++i)
{
try
{
if ( != i)
{
ReleaseConnectionPtr(conptr);
CreateDBConnection(conptr);
}
HRESULT hr = pRecord.CreateInstance(__uuidof(Recordset));
if (SUCCEEDED(hr))
{
pRecord->CursorLocation = adUseClient;
HRESULT ht = pRecord->Open(bSql, _variant_t((IDispatch *)conptr), adOpenDynamic, adLockOptimistic, lOption);
return SUCCEEDED(ht);
}
return false;
}
catch (_com_error&e)
{ }
catch (...)
{
}
}
return false;
} bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, string fieldname, string& strValue)
{
try
{
ASSERT_RECORDSET(pRecord);
_variant_t vart = pRecord->GetCollect(_variant_t(fieldname.c_str()));
strValue = (std::string)(bstr_t)vart;
}
catch (_com_error &)
{
return false;
}
return true;
} CXCADOPOOL * CXCADOPOOL::Instance()
{
if (NULL == _instance)
{
_instance = new CXCADOPOOL;
}
return _instance;
} _ConnectionPtr * CXCADOPOOL::GetTransConnection()
{
_ConnectionPtr *pConptr = this->GetConnectionPtr();
//执行一个查询语句验证下确保当前连接可用
if ((*pConptr)->State != adStateOpen)
{
ReleaseConnectionPtr(*pConptr);
CreateDBConnection(*pConptr);
}
return pConptr;
} void CXCADOPOOL::SendTransCompMsg(_ConnectionPtr *pConptr)
{
PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)pConptr, NULL);
} bool CXCADOPOOL::ExecuteTransSql(_ConnectionPtr *pConptr, _bstr_t bSql)
{
return ExcuteWithoutCheck(*pConptr, bSql);
}
一种利用ADO连接池操作MySQL的解决方案(VC++)的更多相关文章
- Python3 多线程(连接池)操作MySQL插入数据
1.主要模块DBUtils : 允许在多线程应用和数据库之间连接的模块套件Threading : 提供多线程功能 2.创建连接池PooledDB 基本参数: mincached : 最少的空闲连接数, ...
- golang利用beego框架orm操作mysql
GO引入orm框架操作mysql 在beego框架中引入orm操作mysql需要进行的步骤: 第一步:导入orm框架依赖,导入mysql数据库的驱动依赖 import ( "github.c ...
- robot_framewok自动化测试--(9)连接并操作 MySql 数据库
连接并操作 MySql 数据库 1.mysql数据库 1.1安装mysql数据库 请参考我的另一篇文章:MYSQL5.7下载安装图文教程 1.2.准备测试数据 请参考我的另一篇文章:Mysql基础教程 ...
- C++连接mysql的两种方式(ADO连接和mysql api连接)
一.ADO连接mysql 1.安装mysql-5.5.20-win32.msi和mysql-connector-odbc-5.3.4-win32.msi(一般两个安装程序要匹配,否则可能连接不上) ...
- 利用jdbc连接池(利用jdni)
简介 前段时间用jdbc连接池,在这里记录下 1.利用jdni配置数据源 在Web项目的META-INF文件夹中新建context.xml文件,内容为: <?xml version=" ...
- 【JavaWeb】c3p0连接池与MySQL
正文之前 在之前的文章讲到了传统的JDBC连接MySQL的方式,但是这样的方式在进行多个连接时,就显得效率低下,明显不如连接池的效率,所以我们这次来讲解一下JDBC连接池之一:c3p0 正文 1. 准 ...
- MongoDB设置连接池操作百万级以上数据
开发环境 spring 4.3.7 + springBoot 1.5.2 + dubbo 2.6.5 + mongoDB 4.0.0 连接池配置 mongo-pool.properties sprin ...
- redis的连接方法|连接池|操作
1.先看下redis的连接 import redis # 连接服务端 r = redis.Redis(host="127.0.0.1",port=6379) #获取所有的key值 ...
- Java与Scala的两种简易版连接池
Java版简易版连接池: import java.sql.Connection; import java.sql.DriverManager; import java.util.LinkedList; ...
随机推荐
- CF893F:Subtree Minimum Query(线段树合并)
Description 给你一颗有根树,点有权值,m次询问,每次问你某个点的子树中距离其不超过k的点的权值的最小值.(边权均为1,点权有可能重复,k值每次询问有可能不同,强制在线) Input 第一行 ...
- js中使用trim
function trim(s) { return trimRight(trimLeft(s)); } //去掉左边的空白 function trimLeft(s) { if (s == null) ...
- 有关linqtosql和EF的区别
LINQ to SQL和Entity Framework都是一种包含LINQ功能的对象关系映射技术.他们之间的本质区别在于EF对数据库架构和我们查询的类型实行了更好的解耦.使用EF,我们查询的对象不再 ...
- oracle 基本知识点
//创建临时表空间create temporary tablespace test_temp tempfile 'E:\oracle\product\10.2.0\oradata\testserver ...
- Spring源码分析(二十四)初始化非延迟加载单例
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 完成BeanFactory的初始化工作,其中包括ConversionS ...
- PCB直角走线的影响
PCB直角走线的影响 布线(Layout)是PCB设计工程师最基本的工作技能之一.走线的好坏将直接影响到整个系统的性能,大多数高速的设计理论也要最终经过 Layout 得以实现并验证,由此可见,布 ...
- 【vue】vue依赖安装如vue-router、vue-resource、vuex等
方式一: 最直接的方式为在 package.json中添加如图依赖配置,然后项目 cnpm install即可 方式二: 根据vue项目的搭建教程,接下来记录下如何在Vue-cli创建的项目中安装vu ...
- DQL-联合查询
一.含义union:合并.联合,将多次查询结果合并成一个结果二.语法查询语句1union [all]查询语句2union [all]... 三.意义1.将一条比较复杂的查询语句拆分成多条语句2.适用于 ...
- 记一次ss无法上网的排查
从日志开始排查. 登录服务器端 $ ssh root@[IP] 关闭 ss,再次启动并其指定日志输出文件 $ ssserver -c /etc/shadowsocks.json -d stop $ s ...
- WPF实现MDI窗体的方法
原文:WPF实现MDI窗体的方法 第一:新建一个类(Class) Win32Native.cs 代码如下: using System; using System.Collections.Generi ...