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