码迷,mamicode.com
首页 > 数据库 > 详细

一种利用ADO连接池操作MySQL的解决方案(VC++)

时间:2016-12-25 23:59:22      阅读:618      评论:0      收藏:0      [点我收藏+]

标签:资源   recordset   数据库连接池   创建   问题   prot   集中   rda   while   

 VC++连接MySQL数据库 常用的方式有三种:ADO、mysql++,mysql API ; 本文只讲述ADO的连接方式。

      为什么要使用连接池? 对于简单的数据库应用,完全可以先创建一个常连接(此连接永远不关闭,直接数进程退出),但是这样做至少会引起两个问题:(1)资源竞争,多个数据库请求操作不能同时进行,后一请求必须要等到前一请求完成后才能进行;(2)多线程情况下容易出现混乱,甚至出现资源异常释放。还有一种方法,就是使用数据库时创建连接,使用完后关闭连接回收资源。这种方式在数据库操作频繁的情况下会出现严重的效率问题。

数据库连接池

     百度百科给出的解释说明如下:

  数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

   使用数据库连接池至少带来以下几个好处:

  1、资源复用

    数据库连接得到复用,避免了频繁创建、释放引起的系统性能开销。减少了内存碎片以及数据库线程(甚至是进程)的数量。

 2、提高系统响应速度

     由于数据库连接资源得到复用,这毫无疑问会提高系统的整体响应速度。

3、避免资源泄漏

    所有的连接都集中在连接池中统一管理,这可以避免使用单一连接带来的两个问题。

实现原理

  一个较为完备的数据库连接池应具备以下几个条件:

    (1)实始化时创建一定数据量的连接对象放于连接池中。

    (2)连接池对象要有上限。

    (3)连接使用完毕后要放回连接池而不是直接释放掉。

    (4)长期处于空闲态的连接要释放。

最为完整的实现原理请参考百度百科:数据库连接池。

   下面给出一个简单的ADO数据库连接池实现代码:

   (说明:以下代码没有考虑到上述原理的第(4)点,读者请根据自身需要自行实现之。)

  1 //==================头文件 =====================//
  2 //定义数据库连结基本信息结构
  3 typedef struct
  4 {
  5     char    db_ip[20]; //ip地址
  6     uint32  db_port;   //端口
  7     char    db_user[20];//用户
  8     char    db_pwd[32];//密码
  9     char    db_dbname[32];//数据库名
 10 }vos_dbxmlinfo_stru;
 11 
 12 
 13 
 14 class CXCADOPOOL
 15 {    
 16 protected:
 17     CXCADOPOOL();
 18 
 19 public:
 20     virtual ~CXCADOPOOL(void);
 21 
 22     //接口
 23 public:
 24     void    InitConnection(const int iMin, const int iMax);
 25     bool    ExcuteSql(_bstr_t bSql, bool bCheck = true);
 26     bool    GetRecordSet(_bstr_t bSql, _RecordsetPtr& pRecord, long lOption = adCmdText, bool bCheck = true);
 27 
 28 
 29     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, int& nValue);
 30     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, UINT64& unValue);
 31     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, string& strValue);
 32     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, double& fValue);
 33     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, float& fValue);
 34     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, ULONG & nValue);
 35 
 36     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, short& nValue);
 37     bool    GetItemValue(_RecordsetPtr pRecord, long nIndex, unsigned char& nValue);
 38     bool    GetItemValue(_RecordsetPtr pRecord, string fieldname, string& strValue);
 39 
 40     template<class T>
 41     bool    GetItemValue(_RecordsetPtr pRecord, string fieldname, T& tValue);
 42 
 43     static CXCADOPOOL *Instance();
 44     _ConnectionPtr *GetTransConnection();
 45     void    SendTransCompMsg(_ConnectionPtr *pConptr);
 46     bool    ExecuteTransSql(_ConnectionPtr *pConptr, _bstr_t bSql);
 47 private:
 48     bool    CreateDBConnection(_ConnectionPtr & conptr); //返回一个连接 
 49     void    GetConnectionString(string &strConnect);
 50     _ConnectionPtr * GetConnectionPtr();
 51     void    ReleaseConnectionPtr(_ConnectionPtr &conptr);
 52     void    InitDBConfig();
 53     bool    ExcuteWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql);
 54     bool    GetRecordSetWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql, _RecordsetPtr& pRecord, long lOption = adCmdText);
 55     static DWORD WINAPI IdleConnThreadFunc(LPVOID lParam);
 56 private:
 57     
 58     queue<_ConnectionPtr *> m_qConn;
 59     int m_MinConNum;    //最小连接数
 60     int m_MaxConNum;    //最大连接数
 61     int m_CurrentNum;    //当前连接数
 62 
 63     HANDLE          m_Mutex;
 64     HANDLE            m_hEvent;
 65     HANDLE            m_hThread;
 66     DWORD            m_dwThreadId;
 67     HANDLE            m_hThreadEvent;
 68     string                m_strConnect;
 69     static CXCADOPOOL* _instance;
 70 public:
 71     vos_dbxmlinfo_stru    m_stDBInfo;
 72 
 73 };
 74 
 75 template<class T>
 76 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, string fieldname, T& tValue)
 77 {
 78     try
 79     {
 80         ASSERT_RECORDSET(pRecord);
 81         _variant_t vart = pRecord->GetCollect(_variant_t(fieldname.c_str()));
 82         (tValue = (T)(vart));
 83     }
 84     catch (_com_error &)
 85     {
 86         return false;
 87     }
 88     return true;
 89 }
 90  extern CXCADOPOOL *pAdoPool;
 91 //===================.CPP文件=====================//
 92 
 93 bool CXCADOPOOL::GetItemValue( _RecordsetPtr pRecord, long nIndex, int& nValue )
 94 {
 95     try
 96     {
 97         ASSERT_RECORDSET(pRecord);
 98 
 99         nValue = (int)(pRecord->GetFields()->GetItem(nIndex)->Value);
100     }
101     catch (_com_error &)
102     {
103         return false;
104     }
105     return true;
106 }
107 
108 bool  CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, UINT64& unValue)
109 {
110     try
111     {
112         ASSERT_RECORDSET(pRecord);
113 
114         unValue = (UINT64)pRecord->GetFields()->GetItem(nIndex)->Value;
115     }
116     catch (_com_error &)
117     {
118         return false;
119     }
120     return true;
121 }
122 
123 
124 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, ULONG& nValue)
125 {
126 
127     try
128     {
129         ASSERT_RECORDSET(pRecord);
130 
131         nValue = (ULONG)pRecord->GetFields()->GetItem(nIndex)->Value;
132     }
133     catch (_com_error &)
134     {
135         return false;
136     }
137     return true;
138 
139 }
140 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, string& strValue)
141 {
142     try
143     {
144         ASSERT_RECORDSET(pRecord);
145 
146         _variant_t vart = pRecord->GetFields()->GetItem(nIndex)->Value;
147         if (vart.vt == VT_NULL)
148             return true;
149 
150         strValue = (std::string)(bstr_t)vart;
151     }
152     catch (_com_error &)
153     {
154         return false;
155     }
156 
157     return true;
158 }
159 
160 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, double& fValue)
161 {
162     try
163     {
164         ASSERT_RECORDSET(pRecord);
165 
166         fValue = (double)pRecord->GetFields()->GetItem(nIndex)->Value;
167     }
168     catch (_com_error &)
169     {
170         return false;
171     }
172 
173     return true;
174 
175 }
176 
177 
178 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, float& fValue)
179 {
180     try
181     {
182         ASSERT_RECORDSET(pRecord);
183 
184         fValue = (float)pRecord->GetFields()->GetItem(nIndex)->Value;
185     }
186     catch (_com_error &)
187     {
188         return false;
189     }
190     return true;
191 }
192 
193 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, short &sValue)
194 {
195     try
196     {
197         ASSERT_RECORDSET(pRecord);
198         sValue = (short)pRecord->GetFields()->GetItem(nIndex)->Value;
199     }
200     catch (_com_error &)
201     {
202         return false;
203     }
204     return true;
205 }
206 
207 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, long nIndex, unsigned char& cValue)
208 {
209     try
210     {
211         ASSERT_RECORDSET(pRecord);
212         cValue = (unsigned char)pRecord->GetFields()->GetItem(nIndex)->Value;
213     }
214     catch (_com_error &)
215     {
216         return false;
217     }
218     return true;
219 }
220 
221 
222 CXCADOPOOL *pAdoPool = NULL;
223 
224 CXCADOPOOL *CXCADOPOOL::_instance = NULL;
225 
226 
227 CXCADOPOOL::CXCADOPOOL()
228 {
229 
230     ::CoInitialize(NULL);
231 
232     InitDBConfig();
233     GetConnectionString(m_strConnect);
234     m_Mutex = ::CreateMutex(NULL, FALSE, NULL);
235     m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
236     m_CurrentNum = 0;
237 
238     m_hThreadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
239     m_hThread = ::CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)IdleConnThreadFunc, this, 0, &m_dwThreadId);
240     WaitForSingleObject(m_hThreadEvent, INFINITE);
241     CloseHandle(m_hThreadEvent);
242    
245 }
246 
247 CXCADOPOOL::~CXCADOPOOL(void)
248 {
249     ::CoUninitialize();
250 }
251 
252 void CXCADOPOOL::InitConnection(const int iMin, const int iMax)
253 {
254     static bool bInitial = true;
255     if (bInitial)
256     {
257         m_MinConNum = iMin;
258         m_MaxConNum = iMax;
259         for (int i = 0; i < iMin; i++)
260         {
261             _ConnectionPtr *conptr = new _ConnectionPtr;
262             if (CreateDBConnection(*conptr))
263             {
264                 WaitForSingleObject(m_Mutex,INFINITE);
265                 m_qConn.push(conptr);
266                 m_CurrentNum++;
267                 ReleaseMutex(m_Mutex);
268             }
269         }
270         bInitial = false;
271     }
272 }
273         
274 bool CXCADOPOOL::CreateDBConnection(_ConnectionPtr & conptr)
275 {
276     try
277     {
278         //conptr.CreateInstance("ADODB.Connection");
279         conptr.CreateInstance(__uuidof(Connection));
280     
281         HRESULT hr = conptr->Open(m_strConnect.c_str(), "", "", adModeUnknown);
282         if (FAILED(hr))
283         {
284                         return false;
285         }        
286     }
287     catch (_com_error &e)
288     {
289                 return false;
290     }
291     return true;
292 }
293 
294 void CXCADOPOOL::GetConnectionString(string &strConnect)
295 {
296     USES_CONVERSION;
297     CString str;
298     str.Format(_T("Driver=MySQL ODBC 5.3 Unicode Driver;SERVER=%s;UID=%s;PWD=%s;DATABASE=%s;PORT=%d"),
299         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);
300     strConnect = T2A(str);
301 
302 }
303 
304 void CXCADOPOOL::InitDBConfig()
305 {
306     GetPrivateProfileStringA("DBInfo", "host", "localhost", m_stDBInfo.db_ip, 20, ".\\DB.ini");
307     m_stDBInfo.db_port = GetPrivateProfileIntA("DBInfo", "port", 3306, ".\\DB.ini");
308     GetPrivateProfileStringA("DBInfo", "dbname", "", m_stDBInfo.db_dbname, 32, ".\\DB.ini");
309     GetPrivateProfileStringA("DBInfo", "user", "", m_stDBInfo.db_user, 20, ".\\DB.ini");
310 
311     char pbuf_text[255] = { 0 };
312     GetPrivateProfileStringA("DBInfo", "password", "", pbuf_text, 255, ".\\DB.ini");  
313 }
314 
315 bool CXCADOPOOL::ExcuteSql(_bstr_t bSql, bool bCheck)
316 {
317  
326     _ConnectionPtr *conptr = GetConnectionPtr();
327     bool bExec = ExcuteWithoutCheck(*conptr, bSql);
330     PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)conptr,NULL);
331     return bExec;
332 }
333 
334 _ConnectionPtr *  CXCADOPOOL::GetConnectionPtr()
335 {
336     //找出空闲连接
337     while (1)
338     {
339         WaitForSingleObject(m_Mutex, INFINITE);
340         _ConnectionPtr *conptr;
341         if (m_qConn.empty())
342         {
343             if (m_CurrentNum < m_MaxConNum)
344             {
345                 conptr = new _ConnectionPtr;
346                 if (CreateDBConnection(*conptr))
347                 {
348                     m_CurrentNum++;
349                 }
350             }
351             else
352             {
353                 //等待连接释放
354                 ResetEvent(m_hEvent);
355                 ReleaseMutex(m_Mutex);
356                 WaitForSingleObject(m_hEvent, INFINITE);
357                 continue;
358             }
359         }
360         else
361         {
362             conptr = m_qConn.front();
363             m_qConn.pop();
364         }
365 
366         ReleaseMutex(m_Mutex);
367         return conptr;
368     }
369     
370     
371 }
372 
373 DWORD WINAPI CXCADOPOOL::IdleConnThreadFunc(LPVOID lParam)
374 {
375     MSG msg;
376     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
377     CXCADOPOOL *pCXCADOPOOL = static_cast<CXCADOPOOL *>(lParam);
378     SetEvent(pCXCADOPOOL->m_hThreadEvent);
379 
380     while (1)
381     {
382         if (GetMessage(&msg, 0, 0, 0))
383         {
384             switch (msg.message)
385             {
386             case WM_USER_DB_THREAD_MSG:
387             {
388                 _ConnectionPtr *conptr = (_ConnectionPtr *) (msg.wParam);
389             
390                 WaitForSingleObject(pCXCADOPOOL->m_Mutex,INFINITE);
391                 pCXCADOPOOL->m_qConn.push(conptr);
392                 ReleaseMutex(pCXCADOPOOL->m_Mutex);
393                 SetEvent(pCXCADOPOOL->m_hEvent);
394                 
395             }
396             default:
397                 break;
398             }
399         }
400     }
401     return 0;
402 }
403 
404 void CXCADOPOOL::ReleaseConnectionPtr(_ConnectionPtr &conptr)
405 {
406     if (conptr != NULL)
407     {
408         conptr->Close(); //关闭连接
409         conptr.Release(); //释放内存
410         conptr = NULL;
411 
412     }
413 
414 }
415 
416 bool CXCADOPOOL::ExcuteWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql)
417 {
418     int i = 0;
419     while (i < 3)
420     {
421         try
422         {
423             if (0 != i)
424             {
425                 ReleaseConnectionPtr(conptr);
426                 CreateDBConnection(conptr);
427             }
428             ++i;
429             VARIANT nRecordAffected = { 0 };
430             conptr->Execute(bSql, &nRecordAffected, adCmdText);
431             //ReleaseMutex(m_Mutex);
432 
433             if (nRecordAffected.date < 0)
434             {
435                 return false;
436             }
437             break;
438         }
439         catch (_com_error&e)
440         {
441                     }
442         catch (...)
443         {
444                 
445                  }
446     }
447     if (i == 3)
448     {
449        return false;
450     }
451 
452     return true;
453 }
454 
455 bool CXCADOPOOL::GetRecordSet(_bstr_t bSql, _RecordsetPtr& pRecord, long lOption /*= adCmdText*/, bool bCheck)
456 {     465     _ConnectionPtr *conptr = GetConnectionPtr();
466     bool bExec = GetRecordSetWithoutCheck(*conptr, bSql, pRecord,lOption);
467     PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)conptr, NULL);
468     return bExec;
469 }
470 
471 bool CXCADOPOOL::GetRecordSetWithoutCheck(_ConnectionPtr &conptr, _bstr_t bSql, _RecordsetPtr& pRecord, long lOption /*= adCmdText*/)
472 {
473     for (int i = 0; i < 3; ++i)
474     {
475         try
476         {
477             if (0 != i)
478             {
479                 ReleaseConnectionPtr(conptr);
480                 CreateDBConnection(conptr);
481             }
482             HRESULT hr = pRecord.CreateInstance(__uuidof(Recordset));
483             if (SUCCEEDED(hr))
484             {
485                 pRecord->CursorLocation = adUseClient;
486                 HRESULT ht = pRecord->Open(bSql, _variant_t((IDispatch *)conptr), adOpenDynamic, adLockOptimistic, lOption);
487                 return SUCCEEDED(ht);
488             }
489             return false;
490         }
491         catch (_com_error&e)
492         {        }
493         catch (...)
494         {
495                 }
496     }
497     return false;
498 }
499 
500 bool CXCADOPOOL::GetItemValue(_RecordsetPtr pRecord, string fieldname, string& strValue)
501 {
502     try
503     {
504         ASSERT_RECORDSET(pRecord);
505         _variant_t vart = pRecord->GetCollect(_variant_t(fieldname.c_str()));
506         strValue = (std::string)(bstr_t)vart;
507     }
508     catch (_com_error &)
509     {
510         return false;
511     }
512     return true;
513 }
514 
515 CXCADOPOOL * CXCADOPOOL::Instance()
516 {
517     if (NULL == _instance)
518     {
519         _instance = new CXCADOPOOL;
520     }
521     return _instance;
522 }
523 
524 _ConnectionPtr * CXCADOPOOL::GetTransConnection()
525 {
526     _ConnectionPtr *pConptr = this->GetConnectionPtr();
527     //执行一个查询语句验证下确保当前连接可用
528     if ((*pConptr)->State != adStateOpen)
529     {
530         ReleaseConnectionPtr(*pConptr);
531         CreateDBConnection(*pConptr);
532     }
533     return pConptr;
534 }
535 
536 void CXCADOPOOL::SendTransCompMsg(_ConnectionPtr *pConptr)
537 {
538     PostThreadMessage(m_dwThreadId, WM_USER_DB_THREAD_MSG, (WPARAM)pConptr, NULL);
539 }
540 
541 bool CXCADOPOOL::ExecuteTransSql(_ConnectionPtr *pConptr, _bstr_t bSql)
542 {
543   return ExcuteWithoutCheck(*pConptr, bSql);
544 }
545 
546 
547 
548 
549                     

 

 

 

一种利用ADO连接池操作MySQL的解决方案(VC++)

标签:资源   recordset   数据库连接池   创建   问题   prot   集中   rda   while   

原文地址:http://www.cnblogs.com/luisfan/p/6220672.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!