此连接池用于管理数据库的多个连接,主要思想如下:
1)按照传入的参数起N个连接来连接数据库(参数中有最小连接数N,最大连接数M)。
2)建立一个空闲队列(初始化的N个连接放到空闲队列),一个使用队列来管理,使用的时候重空闲队列抓取一个连接,丢到使用队列,
如果空闲队列没有可用连接,并且连接数小于允许的最大连接数(<M)则创建一个新的连接,否则等待。
3)起一个守护线程,发现用过的连接,则使用队列中移除,添加到空闲队列,无效的链接则删除。
代码如下,
首先是头文件,因为导出的是DLL,文件中的RFIDAPI定义如下
#ifdef _USRDLL
#define RFIDAPI _declspec(dllexport)
#else
#define RFIDAPI _declspec(dllimport)
view plaincopy to clipboardprint?
01.// DBConnPool.h: interface for the DBConnPool class.
02.//
03.//
04.#if !defined(AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_)
05.#define AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_
06.#define SQL_BUFFER_LEN 1024
07.#import "C:/Program Files/Common Files/System/ado/msado15.dll" rename("EOF","ADOEOF")
08.#include <list>
09.#include <windows.h>
10.#include <string>
11.#include <vector>
12.#include "DBDefine.h"
13.using namespace ADODB;
14.using namespace std;
15.class RFIDAPI DBConnect
16.{
17.public:
18. DBConnect(LPCSTR strDstAddress,
19. LPCSTR strUsername,
20. LPCSTR strPassword,
21. LPCSTR strDBName,
22. BOOL &state);
23. ~DBConnect();
24.public:
25. // 连接到数据库
26.
27. int Open(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName);
28. // 关闭数据库
29.
30. int Close();
31. // 数据库是否已连接
32.
33. BOOL IsOpen() const;
34.public:
35.private:
36. ADODB::_ConnectionPtr _connection_ptr; //ADO的数据库连接智能指针
37. bool _isAdoValid; //ADO环境是否已经初化成功标志量
38. bool m_bDBOpen;
39.
40. LPCSTR _strDstAddress; //数据源地址或服务名
41. LPCSTR _strUsername; //数据库用户名
42. LPCSTR _strPassword; //数据库密码
43. LPCSTR _strDBName; //数据库名称
44. void VarientToString(_variant_t var, string& str);
45. //对外公共接口
46.public:
47. int GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms);
48.
49. int InsertHistory(int id);
50. int UserLogin(LPCSTR name,LPCSTR password);
51.};
52.typedef std::list<DBConnect*> DBConnectList;
53.class DBConnPool
54.{
55.public:
56. DBConnPool();
57. virtual ~DBConnPool();
58. // 获取实例指针
59. static DBConnPool * Instanse();
60. // 初始化所有连接
61. int InitializeAllDBConnections();
62.
63. // 关闭所有连接
64. void DestroyAllDBConnections();
65. // 获取一个空闲连接
66. DBConnect* GetAConnection();
67. // 交还连接给空闲队列
68. int RestoreAConnection(DBConnect* pDBEngine);
69. void SetDBInfo(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
70.private:
71.
72. // 创建一个连接
73. int InitializeAConnection();
74. // 关闭一个连接
75. void CloseAConnection(DBConnect* pDBEngine);
76. // 停止工作线程
77. void StopThread();
78.
79. // 判断是否需要停止
80. BOOL IsNeedStop();
81. BOOL IsNeedConnection();
82. // 将守卫类作为连接池类的友元类
83. friend class ConnGuard;
84. // 唯一实例
85. static DBConnPool *m_pInstanse;
86.
87. // 空闲数据库连接队列
88. DBConnectList m_listIdleConnection;
89. // 在使用的数据库连接
90. DBConnectList m_listBusyConnection;
91.
92. // 队列保护的临界区
93. CRITICAL_SECTION m_csIdleConnList;
94. CRITICAL_SECTION m_csBusyConnList;
95.
96. // 可用连接总数的三个指标:最大、最小
97. int m_nMaxCount;
98. int m_nMinCount;
99.
100.// // 数据库信息
101. LPCSTR _strDstAddress; //数据源地址或服务名
102. LPCSTR _strUsername; //数据库用户名
103. LPCSTR _strPassword; //数据库密码
104. LPCSTR _strDBName; //数据库名称
105.
106. // 维护线程
107. HANDLE m_hMaintanceThread; // 线程句柄
108. HANDLE m_hHaveData; // 信号
109.
110. BOOL m_bNeedStop; // 管理线程起停的标志位
111. BOOL m_bNeedConnection; // 需要创建连接的标志
112. static DWORD WINAPI thread_run( LPVOID pdata);
113.};
114.// 守卫类,利用构造和析构函数保证连接取出和归还必须成对,防止资源泄露
115.class DBConnGuard
116.{
117.public:
118. DBConnGuard(DBConnect*& DBConn)
119. {
120. DBConn = DBConnPool::Instanse()->GetAConnection();
121. m_pDBConn = DBConn;
122. }
123. virtual ~DBConnGuard()
124. {
125. DBConnPool::Instanse()->RestoreAConnection(m_pDBConn);
126. }
127.private:
128. DBConnect *m_pDBConn;
129.};
130.RFIDAPI void InitDBIterface(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
131.RFIDAPI DBConnect * GetAConnect();
132.#endif // !defined(AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_)
// DBConnPool.h: interface for the DBConnPool class.
//
//
#if !defined(AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_)
#define AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_
#define SQL_BUFFER_LEN 1024
#import "C:/Program Files/Common Files/System/ado/msado15.dll" rename("EOF","ADOEOF")
#include <list>
#include <windows.h>
#include <string>
#include <vector>
#include "DBDefine.h"
using namespace ADODB;
using namespace std;
class RFIDAPI DBConnect
{
public:
DBConnect(LPCSTR strDstAddress,
LPCSTR strUsername,
LPCSTR strPassword,
LPCSTR strDBName,
BOOL &state);
~DBConnect();
public:
// 连接到数据库
int Open(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName);
// 关闭数据库
int Close();
// 数据库是否已连接
BOOL IsOpen() const;
public:
private:
ADODB::_ConnectionPtr _connection_ptr; //ADO的数据库连接智能指针
bool _isAdoValid; //ADO环境是否已经初化成功标志量
bool m_bDBOpen;
LPCSTR _strDstAddress; //数据源地址或服务名
LPCSTR _strUsername; //数据库用户名
LPCSTR _strPassword; //数据库密码
LPCSTR _strDBName; //数据库名称
void VarientToString(_variant_t var, string& str);
//对外公共接口
public:
int GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms);
int InsertHistory(int id);
int UserLogin(LPCSTR name,LPCSTR password);
};
typedef std::list<DBConnect*> DBConnectList;
class DBConnPool
{
public:
DBConnPool();
virtual ~DBConnPool();
// 获取实例指针
static DBConnPool * Instanse();
// 初始化所有连接
int InitializeAllDBConnections();
// 关闭所有连接
void DestroyAllDBConnections();
// 获取一个空闲连接
DBConnect* GetAConnection();
// 交还连接给空闲队列
int RestoreAConnection(DBConnect* pDBEngine);
void SetDBInfo(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
private:
// 创建一个连接
int InitializeAConnection();
// 关闭一个连接
void CloseAConnection(DBConnect* pDBEngine);
// 停止工作线程
void StopThread();
// 判断是否需要停止
BOOL IsNeedStop();
BOOL IsNeedConnection();
// 将守卫类作为连接池类的友元类
friend class ConnGuard;
// 唯一实例
static DBConnPool *m_pInstanse;
// 空闲数据库连接队列
DBConnectList m_listIdleConnection;
// 在使用的数据库连接
DBConnectList m_listBusyConnection;
// 队列保护的临界区
CRITICAL_SECTION m_csIdleConnList;
CRITICAL_SECTION m_csBusyConnList;
// 可用连接总数的三个指标:最大、最小
int m_nMaxCount;
int m_nMinCount;
// // 数据库信息
LPCSTR _strDstAddress; //数据源地址或服务名
LPCSTR _strUsername; //数据库用户名
LPCSTR _strPassword; //数据库密码
LPCSTR _strDBName; //数据库名称
// 维护线程
HANDLE m_hMaintanceThread; // 线程句柄
HANDLE m_hHaveData; // 信号
BOOL m_bNeedStop; // 管理线程起停的标志位
BOOL m_bNeedConnection; // 需要创建连接的标志
static DWORD WINAPI thread_run( LPVOID pdata);
};
// 守卫类,利用构造和析构函数保证连接取出和归还必须成对,防止资源泄露
class DBConnGuard
{
public:
DBConnGuard(DBConnect*& DBConn)
{
DBConn = DBConnPool::Instanse()->GetAConnection();
m_pDBConn = DBConn;
}
virtual ~DBConnGuard()
{
DBConnPool::Instanse()->RestoreAConnection(m_pDBConn);
}
private:
DBConnect *m_pDBConn;
};
RFIDAPI void InitDBIterface(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
RFIDAPI DBConnect * GetAConnect();
#endif // !defined(AFX_DBCONNPOOL_H__42089E9A_FD85_4DD4_A973_64A4980332A5__INCLUDED_)
下面是实现文件,
view plaincopy to clipboardprint?
01.// DBConnPool.cpp: implementation of the DBConnPool class.
02.//
03.//
04.#include "stdafx.h"
05.#include "DBConnPool.h"
06.DBConnect * pDBConn = NULL;
07.void InitDBIterface(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
08.{
09. DBConnPool::Instanse()->SetDBInfo(strDstAddress,strUsername,strPassword,strDBName,minConn,maxConn);
10. int cout = DBConnPool::Instanse()->InitializeAllDBConnections();
11.}
12.DBConnect * GetAConnect()
13.{
14. DBConnGuard oConnGuard(pDBConn);
15. return pDBConn;
16.}
17.//DBConnect/
18.DBConnect::DBConnect(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName,BOOL &state)
19.{
20. m_bDBOpen = false;
21. if (0 == Open(strDstAddress,strUsername,strPassword,strDBName))
22. {
23. state =true;
24. }
25. else
26. {
27. state = false;
28. }
29.}
30.DBConnect::~DBConnect()
31.{
32. Close();
33.}
34.int DBConnect::Open(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName)
35.{
36. _strDstAddress = strDstAddress;
37. _strDBName = strDBName;
38. _strUsername = strUsername;
39. _strPassword = strPassword;
40.
41. HRESULT comhr = ::CoInitialize(NULL);
42. if (FAILED(comhr))
43.
44. {
45. return -1;
46. }
47. HRESULT hr = _connection_ptr.CreateInstance(__uuidof(Connection));
48.
49. if (FAILED(hr))
50. {
51. return -1;
52. }
53.
54. char szSQL[SQL_BUFFER_LEN] = {0};
55. memset(szSQL, 0, SQL_BUFFER_LEN);
56. sprintf(szSQL, "Driver=SQL Server;Server=%s;DATABASE=%s", strDstAddress, strDBName);
57.
58. try
59. {
60. // 连接到服务器上数据库
61. _connection_ptr->Open(szSQL, strUsername, strPassword,adModeUnknown) ;
62. if (FAILED(hr))
63. return -1;
64. }
65. catch (_com_error &err)
66. {
67. TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
68.
69. return -1;
70. }
71.
72. m_bDBOpen = TRUE;
73.
74. return 0;
75.}
76.int DBConnect::Close()
77.{
78. if (m_bDBOpen)
79. {
80. HRESULT hr =_connection_ptr->Close();
81.
82. if (FAILED(hr))
83. {
84. return -1;
85. }
86. ::CoUninitialize();
87. m_bDBOpen = FALSE;
88. }
89.
90. return 0;
91.}
92.int DBConnect::UserLogin(LPCSTR name,LPCSTR password)
93.{
94. if (!m_bDBOpen)
95. {
96. return -1;
97. }
98. // 创建Command对象
99. _CommandPtr cmd;
100. HRESULT hr = cmd.CreateInstance(__uuidof(Command));
101. if (FAILED(hr))
102. {
103. return -1;
104. }
105.
106. char szSQL[SQL_BUFFER_LEN] = {0};
107. sprintf(szSQL, "select count(*) as count from t_user where name =/'%s/' and password =/'%s/'",
108. name,password);
109. cmd->ActiveConnection = _connection_ptr;
110. cmd->CommandText = _bstr_t(szSQL);
111. cmd->CommandType = adCmdText;
112. try
113. {
114. _RecordsetPtr rs = cmd->Execute(NULL, NULL, adCmdUnknown);
115.
116. if (FAILED(hr))
117. {
118. return -1;
119. }
120. _variant_t count;
121. while (!rs->ADOEOF)
122. {
123. count = rs->GetCollect("count");
124. rs->MoveNext() ;
125. }
126. if(count.intVal == 0)
127. return -1;
128. }
129. catch (_com_error &err)
130. {
131. TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
132.
133. return -1;
134. }
135. return 0;
136.}
137.int DBConnect::GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms)
138.{
139. if (!m_bDBOpen)
140. {
141. return -1;
142. }
143. // 创建Command对象
144. _CommandPtr cmd;
145. HRESULT hr = cmd.CreateInstance(__uuidof(Command));
146. if (FAILED(hr))
147. {
148. return -1;
149. }
150. string strSql = "exec SP_SMS_GETSUBMIT";
151. cmd->ActiveConnection = _connection_ptr;
152. cmd->CommandText = _bstr_t(strSql.c_str());
153. cmd->CommandType = adCmdText;
154. try
155. {
156. _RecordsetPtr rs = cmd->Execute(NULL, NULL, adCmdUnknown);
157.
158. if (FAILED(hr))
159. {
160. return -1;
161. }
162. while (!rs->ADOEOF)
163. {
164. _variant_t id;
165. _variant_t recverid;
166. _variant_t recvertel;
167. _variant_t messagecontent;
168. _variant_t recverphonetype;
169. _variant_t inout;
170. _variant_t sendtime;
171. _variant_t cardtime;
172. _variant_t schoolid;
173. _variant_t classid;
174. _variant_t rfidno;
175.
176. id = rs->GetCollect("id");
177. recverid = rs->GetCollect("recverid");
178. recvertel = rs->GetCollect("recvertel");
179. messagecontent = rs->GetCollect("messagecontent");
180. recverphonetype = rs->GetCollect("recverphonetype");
181. inout = rs->GetCollect("inout");
182. sendtime = rs->GetCollect("sendtime");
183. cardtime = rs->GetCollect("cardtime");
184. schoolid = rs->GetCollect("schoolid");
185. classid = rs->GetCollect("classid");
186. rfidno = rs->GetCollect("rfidno");
187. SOAP_SUBMIT_SMS submitsms;
188. submitsms.id = (int)(long)id;
189. VarientToString(recverid, submitsms.recverid);
190. VarientToString(recvertel, submitsms.recvertel);
191. VarientToString(messagecontent, submitsms.messagecontent);
192. VarientToString(recverphonetype, submitsms.recverphonetype);
193. submitsms.inout = (int)(long)inout;
194. VarientToString(sendtime, submitsms.sendtime);
195. VarientToString(cardtime, submitsms.cardtime);
196. VarientToString(rfidno, submitsms.rfidno);
197. submitsms.schoolid = (int)(long)schoolid;
198. submitsms.classid = (int)(long)classid;
199. vecsoapSms.push_back(submitsms);
200. rs->MoveNext() ;
201. }
202. }
203. catch (_com_error &err)
204. {
205. TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
206.
207. return -1;
208. }
209. return 0;
210.}
211.int DBConnect::InsertHistory(int id)
212.{
213. if (!m_bDBOpen)
214. {
215. return -1;
216. }
217. // 创建Command对象
218. _CommandPtr cmd;
219. HRESULT hr = cmd.CreateInstance(__uuidof(Command));
220. if (FAILED(hr))
221. {
222. return -1;
223. }
224. char szSQL[SQL_BUFFER_LEN] = {0};
225. sprintf(szSQL, "exec SP_SMS_SUBMITRESULT %d", id);
226. try
227. {
228. cmd->ActiveConnection = _connection_ptr;
229. cmd->CommandText = _bstr_t(szSQL);
230. cmd->CommandType = adCmdText;
231. cmd->Execute(NULL, NULL, adCmdUnknown);
232. }
233. catch (_com_error &err)
234. {
235. TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
236.
237. return -1;
238. }
239. return 0;
240.}
241.void DBConnect::VarientToString(_variant_t var, string& str)
242.{
243. if (VT_NULL == var.vt)
244. {
245. str = "";
246. }
247. else
248. {
249. str = (char*)_bstr_t(var);
250. }
251.}
252.//End//
253.//
254.// Construction/Destruction
255.//
256.DBConnPool* DBConnPool::m_pInstanse = NULL;
257.DBConnPool::DBConnPool()
258.{
259. m_bNeedStop = FALSE;
260. m_bNeedConnection = FALSE;
261. m_hMaintanceThread = INVALID_HANDLE_VALUE;
262.
263. // 线程控制
264. m_hHaveData = CreateEvent (NULL, TRUE, FALSE, _T("DataConnPool"));
265.
266.
267. InitializeCriticalSection(&m_csIdleConnList);
268. InitializeCriticalSection(&m_csBusyConnList);
269.}
270.void DBConnPool::SetDBInfo(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
271.{
272. _strDBName = strDBName;
273. _strDstAddress = strDstAddress;
274. _strPassword = strPassword;
275. _strUsername = strUsername;
276. m_nMaxCount = maxConn;
277. m_nMinCount = minConn;
278.}
279.DBConnPool::~DBConnPool()
280.{
281. m_hMaintanceThread = INVALID_HANDLE_VALUE;
282. m_bNeedStop = TRUE;
283. CloseHandle(m_hHaveData);
284. CloseHandle(m_hMaintanceThread);
285.
286. DeleteCriticalSection(&m_csIdleConnList);
287. DeleteCriticalSection(&m_csBusyConnList);
288.}
289.DBConnPool *DBConnPool::Instanse()
290.{
291. if (NULL == m_pInstanse)
292. {
293. m_pInstanse = new DBConnPool();
294. }
295. return m_pInstanse;
296.}
297.int DBConnPool::InitializeAllDBConnections()
298.{
299. // 先七公里现有的数据
300. DestroyAllDBConnections();
301. // 开始按照最小数量开始创建
302. DBConnect * pDBConnect = NULL;
303. int nCount = 0;
304. for (int i = 0; i < m_nMinCount; i++)
305. {
306. nCount = InitializeAConnection();
307. }
308. // 创建一个工作线程,用来进行一些后台维护工作
309. if (INVALID_HANDLE_VALUE == m_hMaintanceThread)
310. {
311. m_hMaintanceThread = CreateThread(NULL, NULL, thread_run, (LPVOID)this, 0, NULL);
312. }
313. return nCount;
314.}
315.void DBConnPool::DestroyAllDBConnections()
316.{
317. // 销毁数据库连接可以使用大锁
318. EnterCriticalSection(&m_csIdleConnList);
319. DBConnectList::iterator itIdle = m_listIdleConnection.begin();
320. DBConnectList::iterator itIdleEnd = m_listIdleConnection.end();
321. while (itIdle != itIdleEnd)
322. {
323. if (NULL != (*itIdle))
324. {
325. (*itIdle)->Close();
326. delete (*itIdle);
327. }
328. // erase本身就会把跌代器指向下一个
329. itIdle = m_listIdleConnection.erase(itIdle);
330. }
331. LeaveCriticalSection(&m_csIdleConnList);
332. // 还有使用中的连接
333. EnterCriticalSection(&m_csBusyConnList);
334. DBConnectList::iterator itBusy = m_listBusyConnection.begin();
335. DBConnectList::iterator itBusyEnd = m_listBusyConnection.end();
336. while (itBusy != itBusyEnd)
337. {
338. if (NULL != (*itBusy))
339. {
340. (*itBusy)->Close();
341. delete (*itBusy);
342. }
343. // erase本身就会把跌代器指向下一个
344. itBusy = m_listBusyConnection.erase(itBusy);
345. }
346. LeaveCriticalSection(&m_csBusyConnList);
347.}
348.int DBConnPool::InitializeAConnection()
349.{
350. BOOL bSuccess = FALSE;
351. DBConnect * pDBEngine = new DBConnect(_strDstAddress, _strUsername, _strPassword, _strDBName, bSuccess);
352. if (bSuccess)
353. {
354. m_bNeedConnection = FALSE;
355. return RestoreAConnection(pDBEngine);
356. }
357. else
358. {
359. delete pDBEngine;
360. return m_listIdleConnection.size();
361. }
362.}
363.void DBConnPool::CloseAConnection(DBConnect* pDBEngine)
364.{
365. pDBEngine->Close();
366. // 从空闲队列将其删除
367. EnterCriticalSection(&m_csIdleConnList);
368. m_listIdleConnection.remove(pDBEngine);
369. LeaveCriticalSection(&m_csIdleConnList);
370.}
371.DBConnect * DBConnPool::GetAConnection()
372.{
373. DBConnect * pDBEngine = NULL;
374. // 做一个循环,反复尝试五次取连接,每次间隔1秒钟
375. int nTimes = 0;
376. while ((m_listIdleConnection.size() <= 0) && (nTimes < 5))
377. {
378. Sleep(1000);
379. nTimes++;
380. }
381. if (5 == nTimes)
382. {
383. // 这样狼狈的进来肯定是没有可用连接了,记录日志退出
384. // g_pSvrLog->AddRunLog(LL_ERROR, _T("Waiting for a connection for a long time, but failed."));
385. return pDBEngine;
386. }
387. // 从空闲队列中取出,并且加入到使用队列中
388. EnterCriticalSection(&m_csIdleConnList);
389. if (m_listIdleConnection.size() > 0)
390. {
391. pDBEngine = m_listIdleConnection.front();
392. m_listIdleConnection.pop_front();
393. // 加入使用的连接队列
394. EnterCriticalSection(&m_csBusyConnList);
395. m_listBusyConnection.push_back(pDBEngine);
396. LeaveCriticalSection(&m_csBusyConnList);
397. }
398. LeaveCriticalSection(&m_csIdleConnList);
399. if (m_listIdleConnection.size() <= 1)
400. {
401. // 剩余空闲连接的数目小于等于1个时候需要检查开始创建
402. if ((m_listIdleConnection.size() + m_listBusyConnection.size()) < m_nMaxCount)
403. {
404. // 还小于最大限制,可以创建
405. SetEvent(m_hHaveData);
406. m_bNeedConnection = TRUE;
407. }
408. else
409. {
410. // 超出限制了,做个记录吧
411. //g_pSvrLog->AddRunLog(LL_ERROR, _T("Database connection reached max count."));
412. }
413. }
414. return pDBEngine;
415.}
416.int DBConnPool::RestoreAConnection(DBConnect* pDBEngine)
417.{
418. if (NULL != pDBEngine)
419. {
420. // 从使用中的队列取出
421. EnterCriticalSection(&m_csBusyConnList);
422. m_listBusyConnection.remove(pDBEngine);
423. LeaveCriticalSection(&m_csBusyConnList);
424. // 加入到空闲队列中
425. EnterCriticalSection(&m_csIdleConnList);
426. m_listIdleConnection.push_back(pDBEngine);
427. LeaveCriticalSection(&m_csIdleConnList);
428. }
429. EnterCriticalSection(&m_csIdleConnList);
430. int nCount = m_listIdleConnection.size();
431. LeaveCriticalSection(&m_csIdleConnList);
432. return nCount;
433.}
434.void DBConnPool::StopThread()
435.{
436. m_bNeedStop = TRUE;
437. // 因为线程是无限制等待信号的,所以这里先把标志位置为停止,然后发信号让线程检测
438. SetEvent(m_hHaveData);
439. // 等待退出
440. WaitForSingleObject(m_hMaintanceThread, INFINITE);
441. CloseHandle(m_hMaintanceThread);
442.}
443.BOOL DBConnPool::IsNeedStop()
444.{
445. return m_bNeedStop;
446.}
447.BOOL DBConnPool::IsNeedConnection()
448.{
449. return m_bNeedConnection;
450.}
451./************************************************************************/
452./* 维护线程 */
453./************************************************************************/
454.DWORD WINAPI DBConnPool::thread_run( LPVOID pdata)
455.{
456. DBConnPool * pConPool = (DBConnPool *) pdata;
457. while (!pConPool->IsNeedStop())
458. {
459. // 设置事件为无信号, 并且无限制等待
460. ResetEvent(pConPool->m_hHaveData);
461. WaitForSingleObject(pConPool->m_hHaveData, INFINITE);
462. if (pConPool->IsNeedConnection())
463. {
464. // g_pSvrLog->AddRunLog(LL_DEBUG, _T("Create a new DB connection."));
465. pConPool->InitializeAConnection();
466. }
467. }
468. return 0;
469.}
// DBConnPool.cpp: implementation of the DBConnPool class.
//
//
#include "stdafx.h"
#include "DBConnPool.h"
DBConnect * pDBConn = NULL;
void InitDBIterface(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
{
DBConnPool::Instanse()->SetDBInfo(strDstAddress,strUsername,strPassword,strDBName,minConn,maxConn);
int cout = DBConnPool::Instanse()->InitializeAllDBConnections();
}
DBConnect * GetAConnect()
{
DBConnGuard oConnGuard(pDBConn);
return pDBConn;
}
//DBConnect/
DBConnect::DBConnect(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName,BOOL &state)
{
m_bDBOpen = false;
if (0 == Open(strDstAddress,strUsername,strPassword,strDBName))
{
state =true;
}
else
{
state = false;
}
}
DBConnect::~DBConnect()
{
Close();
}
int DBConnect::Open(LPCTSTR strDstAddress, LPCTSTR strUsername, LPCTSTR strPassword, LPCTSTR strDBName)
{
_strDstAddress = strDstAddress;
_strDBName = strDBName;
_strUsername = strUsername;
_strPassword = strPassword;
HRESULT comhr = ::CoInitialize(NULL);
if (FAILED(comhr))
{
return -1;
}
HRESULT hr = _connection_ptr.CreateInstance(__uuidof(Connection));
if (FAILED(hr))
{
return -1;
}
char szSQL[SQL_BUFFER_LEN] = {0};
memset(szSQL, 0, SQL_BUFFER_LEN);
sprintf(szSQL, "Driver=SQL Server;Server=%s;DATABASE=%s", strDstAddress, strDBName);
try
{
// 连接到服务器上数据库
_connection_ptr->Open(szSQL, strUsername, strPassword,adModeUnknown) ;
if (FAILED(hr))
return -1;
}
catch (_com_error &err)
{
TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
return -1;
}
m_bDBOpen = TRUE;
return 0;
}
int DBConnect::Close()
{
if (m_bDBOpen)
{
HRESULT hr =_connection_ptr->Close();
if (FAILED(hr))
{
return -1;
}
::CoUninitialize();
m_bDBOpen = FALSE;
}
return 0;
}
int DBConnect::UserLogin(LPCSTR name,LPCSTR password)
{
if (!m_bDBOpen)
{
return -1;
}
// 创建Command对象
_CommandPtr cmd;
HRESULT hr = cmd.CreateInstance(__uuidof(Command));
if (FAILED(hr))
{
return -1;
}
char szSQL[SQL_BUFFER_LEN] = {0};
sprintf(szSQL, "select count(*) as count from t_user where name =/'%s/' and password =/'%s/'",
name,password);
cmd->ActiveConnection = _connection_ptr;
cmd->CommandText = _bstr_t(szSQL);
cmd->CommandType = adCmdText;
try
{
_RecordsetPtr rs = cmd->Execute(NULL, NULL, adCmdUnknown);
if (FAILED(hr))
{
return -1;
}
_variant_t count;
while (!rs->ADOEOF)
{
count = rs->GetCollect("count");
rs->MoveNext() ;
}
if(count.intVal == 0)
return -1;
}
catch (_com_error &err)
{
TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
return -1;
}
return 0;
}
int DBConnect::GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms)
{
if (!m_bDBOpen)
{
return -1;
}
// 创建Command对象
_CommandPtr cmd;
HRESULT hr = cmd.CreateInstance(__uuidof(Command));
if (FAILED(hr))
{
return -1;
}
string strSql = "exec SP_SMS_GETSUBMIT";
cmd->ActiveConnection = _connection_ptr;
cmd->CommandText = _bstr_t(strSql.c_str());
cmd->CommandType = adCmdText;
try
{
_RecordsetPtr rs = cmd->Execute(NULL, NULL, adCmdUnknown);
if (FAILED(hr))
{
return -1;
}
while (!rs->ADOEOF)
{
_variant_t id;
_variant_t recverid;
_variant_t recvertel;
_variant_t messagecontent;
_variant_t recverphonetype;
_variant_t inout;
_variant_t sendtime;
_variant_t cardtime;
_variant_t schoolid;
_variant_t classid;
_variant_t rfidno;
id = rs->GetCollect("id");
recverid = rs->GetCollect("recverid");
recvertel = rs->GetCollect("recvertel");
messagecontent = rs->GetCollect("messagecontent");
recverphonetype = rs->GetCollect("recverphonetype");
inout = rs->GetCollect("inout");
sendtime = rs->GetCollect("sendtime");
cardtime = rs->GetCollect("cardtime");
schoolid = rs->GetCollect("schoolid");
classid = rs->GetCollect("classid");
rfidno = rs->GetCollect("rfidno");
SOAP_SUBMIT_SMS submitsms;
submitsms.id = (int)(long)id;
VarientToString(recverid, submitsms.recverid);
VarientToString(recvertel, submitsms.recvertel);
VarientToString(messagecontent, submitsms.messagecontent);
VarientToString(recverphonetype, submitsms.recverphonetype);
submitsms.inout = (int)(long)inout;
VarientToString(sendtime, submitsms.sendtime);
VarientToString(cardtime, submitsms.cardtime);
VarientToString(rfidno, submitsms.rfidno);
submitsms.schoolid = (int)(long)schoolid;
submitsms.classid = (int)(long)classid;
vecsoapSms.push_back(submitsms);
rs->MoveNext() ;
}
}
catch (_com_error &err)
{
TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
return -1;
}
return 0;
}
int DBConnect::InsertHistory(int id)
{
if (!m_bDBOpen)
{
return -1;
}
// 创建Command对象
_CommandPtr cmd;
HRESULT hr = cmd.CreateInstance(__uuidof(Command));
if (FAILED(hr))
{
return -1;
}
char szSQL[SQL_BUFFER_LEN] = {0};
sprintf(szSQL, "exec SP_SMS_SUBMITRESULT %d", id);
try
{
cmd->ActiveConnection = _connection_ptr;
cmd->CommandText = _bstr_t(szSQL);
cmd->CommandType = adCmdText;
cmd->Execute(NULL, NULL, adCmdUnknown);
}
catch (_com_error &err)
{
TRACE(_T("数据库操作失败! 错误信息:%s, 文件:%s, 行:%d./n"), err.ErrorMessage(), __FILE__, __LINE__);
return -1;
}
return 0;
}
void DBConnect::VarientToString(_variant_t var, string& str)
{
if (VT_NULL == var.vt)
{
str = "";
}
else
{
str = (char*)_bstr_t(var);
}
}
//End//
//
// Construction/Destruction
//
DBConnPool* DBConnPool::m_pInstanse = NULL;
DBConnPool::DBConnPool()
{
m_bNeedStop = FALSE;
m_bNeedConnection = FALSE;
m_hMaintanceThread = INVALID_HANDLE_VALUE;
// 线程控制
m_hHaveData = CreateEvent (NULL, TRUE, FALSE, _T("DataConnPool"));
InitializeCriticalSection(&m_csIdleConnList);
InitializeCriticalSection(&m_csBusyConnList);
}
void DBConnPool::SetDBInfo(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
{
_strDBName = strDBName;
_strDstAddress = strDstAddress;
_strPassword = strPassword;
_strUsername = strUsername;
m_nMaxCount = maxConn;
m_nMinCount = minConn;
}
DBConnPool::~DBConnPool()
{
m_hMaintanceThread = INVALID_HANDLE_VALUE;
m_bNeedStop = TRUE;
CloseHandle(m_hHaveData);
CloseHandle(m_hMaintanceThread);
DeleteCriticalSection(&m_csIdleConnList);
DeleteCriticalSection(&m_csBusyConnList);
}
DBConnPool *DBConnPool::Instanse()
{
if (NULL == m_pInstanse)
{
m_pInstanse = new DBConnPool();
}
return m_pInstanse;
}
int DBConnPool::InitializeAllDBConnections()
{
// 先七公里现有的数据
DestroyAllDBConnections();
// 开始按照最小数量开始创建
DBConnect * pDBConnect = NULL;
int nCount = 0;
for (int i = 0; i < m_nMinCount; i++)
{
nCount = InitializeAConnection();
}
// 创建一个工作线程,用来进行一些后台维护工作
if (INVALID_HANDLE_VALUE == m_hMaintanceThread)
{
m_hMaintanceThread = CreateThread(NULL, NULL, thread_run, (LPVOID)this, 0, NULL);
}
return nCount;
}
void DBConnPool::DestroyAllDBConnections()
{
// 销毁数据库连接可以使用大锁
EnterCriticalSection(&m_csIdleConnList);
DBConnectList::iterator itIdle = m_listIdleConnection.begin();
DBConnectList::iterator itIdleEnd = m_listIdleConnection.end();
while (itIdle != itIdleEnd)
{
if (NULL != (*itIdle))
{
(*itIdle)->Close();
delete (*itIdle);
}
// erase本身就会把跌代器指向下一个
itIdle = m_listIdleConnection.erase(itIdle);
}
LeaveCriticalSection(&m_csIdleConnList);
// 还有使用中的连接
EnterCriticalSection(&m_csBusyConnList);
DBConnectList::iterator itBusy = m_listBusyConnection.begin();
DBConnectList::iterator itBusyEnd = m_listBusyConnection.end();
while (itBusy != itBusyEnd)
{
if (NULL != (*itBusy))
{
(*itBusy)->Close();
delete (*itBusy);
}
// erase本身就会把跌代器指向下一个
itBusy = m_listBusyConnection.erase(itBusy);
}
LeaveCriticalSection(&m_csBusyConnList);
}
int DBConnPool::InitializeAConnection()
{
BOOL bSuccess = FALSE;
DBConnect * pDBEngine = new DBConnect(_strDstAddress, _strUsername, _strPassword, _strDBName, bSuccess);
if (bSuccess)
{
m_bNeedConnection = FALSE;
return RestoreAConnection(pDBEngine);
}
else
{
delete pDBEngine;
return m_listIdleConnection.size();
}
}
void DBConnPool::CloseAConnection(DBConnect* pDBEngine)
{
pDBEngine->Close();
// 从空闲队列将其删除
EnterCriticalSection(&m_csIdleConnList);
m_listIdleConnection.remove(pDBEngine);
LeaveCriticalSection(&m_csIdleConnList);
}
DBConnect * DBConnPool::GetAConnection()
{
DBConnect * pDBEngine = NULL;
// 做一个循环,反复尝试五次取连接,每次间隔1秒钟
int nTimes = 0;
while ((m_listIdleConnection.size() <= 0) && (nTimes < 5))
{
Sleep(1000);
nTimes++;
}
if (5 == nTimes)
{
// 这样狼狈的进来肯定是没有可用连接了,记录日志退出
// g_pSvrLog->AddRunLog(LL_ERROR, _T("Waiting for a connection for a long time, but failed."));
return pDBEngine;
}
// 从空闲队列中取出,并且加入到使用队列中
EnterCriticalSection(&m_csIdleConnList);
if (m_listIdleConnection.size() > 0)
{
pDBEngine = m_listIdleConnection.front();
m_listIdleConnection.pop_front();
// 加入使用的连接队列
EnterCriticalSection(&m_csBusyConnList);
m_listBusyConnection.push_back(pDBEngine);
LeaveCriticalSection(&m_csBusyConnList);
}
LeaveCriticalSection(&m_csIdleConnList);
if (m_listIdleConnection.size() <= 1)
{
// 剩余空闲连接的数目小于等于1个时候需要检查开始创建
if ((m_listIdleConnection.size() + m_listBusyConnection.size()) < m_nMaxCount)
{
// 还小于最大限制,可以创建
SetEvent(m_hHaveData);
m_bNeedConnection = TRUE;
}
else
{
// 超出限制了,做个记录吧
//g_pSvrLog->AddRunLog(LL_ERROR, _T("Database connection reached max count."));
}
}
return pDBEngine;
}
int DBConnPool::RestoreAConnection(DBConnect* pDBEngine)
{
if (NULL != pDBEngine)
{
// 从使用中的队列取出
EnterCriticalSection(&m_csBusyConnList);
m_listBusyConnection.remove(pDBEngine);
LeaveCriticalSection(&m_csBusyConnList);
// 加入到空闲队列中
EnterCriticalSection(&m_csIdleConnList);
m_listIdleConnection.push_back(pDBEngine);
LeaveCriticalSection(&m_csIdleConnList);
}
EnterCriticalSection(&m_csIdleConnList);
int nCount = m_listIdleConnection.size();
LeaveCriticalSection(&m_csIdleConnList);
return nCount;
}
void DBConnPool::StopThread()
{
m_bNeedStop = TRUE;
// 因为线程是无限制等待信号的,所以这里先把标志位置为停止,然后发信号让线程检测
SetEvent(m_hHaveData);
// 等待退出
WaitForSingleObject(m_hMaintanceThread, INFINITE);
CloseHandle(m_hMaintanceThread);
}
BOOL DBConnPool::IsNeedStop()
{
return m_bNeedStop;
}
BOOL DBConnPool::IsNeedConnection()
{
return m_bNeedConnection;
}
/************************************************************************/
/* 维护线程 */
/************************************************************************/
DWORD WINAPI DBConnPool::thread_run( LPVOID pdata)
{
DBConnPool * pConPool = (DBConnPool *) pdata;
while (!pConPool->IsNeedStop())
{
// 设置事件为无信号, 并且无限制等待
ResetEvent(pConPool->m_hHaveData);
WaitForSingleObject(pConPool->m_hHaveData, INFINITE);
if (pConPool->IsNeedConnection())
{
// g_pSvrLog->AddRunLog(LL_DEBUG, _T("Create a new DB connection."));
pConPool->InitializeAConnection();
}
}
return 0;
}
为了使用方便,使用的时候,自己定义个类来初始化连接以及所使用的接口,
例如,,定义个DBinterface的类
头文件中这样写
view plaincopy to clipboardprint?
01.// DBInterface.h: interface for the DBInterface class.
02.//
03.//
04.#if !defined(AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_)
05.#define AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_
06.#if _MSC_VER > 1000
07.#pragma once
08.#endif // _MSC_VER > 1000
09.#include "DBDefine.h"
10.#include "DBConnPool.h"
11.#if defined(__cplusplus)
12.extern "C"
13.{
14.#endif
15.
16. // Initialize RS Receiver
17. RFIDAPI DWORD InItDBConnPool(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
18. RFIDAPI void GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms);
19. RFIDAPI void InsertHistory(int id);
20. RFIDAPI int UserLogin(LPCSTR name,LPCSTR password);
21.
22. // Initialize Sock Receiver
23.
24.#if defined(__cplusplus)
25.}
26.#endif
27.#endif // !defined(AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_)
// DBInterface.h: interface for the DBInterface class.
//
//
#if !defined(AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_)
#define AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "DBDefine.h"
#include "DBConnPool.h"
#if defined(__cplusplus)
extern "C"
{
#endif
// Initialize RS Receiver
RFIDAPI DWORD InItDBConnPool(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn);
RFIDAPI void GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms);
RFIDAPI void InsertHistory(int id);
RFIDAPI int UserLogin(LPCSTR name,LPCSTR password);
// Initialize Sock Receiver
#if defined(__cplusplus)
}
#endif
#endif // !defined(AFX_DBINTERFACE_H__E761F9FE_39EE_40A2_88D1_7FCBB97A145A__INCLUDED_)
实现文件如下
view plaincopy to clipboardprint?
01.// DBInterface.cpp : Defines the entry point for the DLL application.
02.// */
03./************************************************************************/
04.#include "stdafx.h"
05.#include "DBInterface.h"
06.DWORD InItDBConnPool(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
07.{
08. DBConnPool::Instanse()->SetDBInfo(strDstAddress,strUsername,strPassword,strDBName,minConn,maxConn);
09. return DBConnPool::Instanse()->InitializeAllDBConnections();
10.}
11.void GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms)
12.{
13. DBConnect *pDBConn = NULL;
14. DBConnGuard oConnGuard(pDBConn);
15. pDBConn->GetSubmitInfo(vecsoapSms);
16.}
17.void InsertHistory(int id)
18.{
19. DBConnect *pDBConn = NULL;
20. DBConnGuard oConnGuard(pDBConn);
21. pDBConn->InsertHistory(id);
22.}
23.int UserLogin(LPCSTR name,LPCSTR password)
24.{
25. DBConnect *pDBConn = NULL;
26. DBConnGuard oConnGuard(pDBConn);
27. return pDBConn->UserLogin(name,password);
28.}
// DBInterface.cpp : Defines the entry point for the DLL application.
// */
/************************************************************************/
#include "stdafx.h"
#include "DBInterface.h"
DWORD InItDBConnPool(LPCSTR strDstAddress, LPCSTR strUsername, LPCSTR strPassword, LPCSTR strDBName,int minConn,int maxConn)
{
DBConnPool::Instanse()->SetDBInfo(strDstAddress,strUsername,strPassword,strDBName,minConn,maxConn);
return DBConnPool::Instanse()->InitializeAllDBConnections();
}
void GetSubmitInfo(vector<SOAP_SUBMIT_SMS> &vecsoapSms)
{
DBConnect *pDBConn = NULL;
DBConnGuard oConnGuard(pDBConn);
pDBConn->GetSubmitInfo(vecsoapSms);
}
void InsertHistory(int id)
{
DBConnect *pDBConn = NULL;
DBConnGuard oConnGuard(pDBConn);
pDBConn->InsertHistory(id);
}
int UserLogin(LPCSTR name,LPCSTR password)
{
DBConnect *pDBConn = NULL;
DBConnGuard oConnGuard(pDBConn);
return pDBConn->UserLogin(name,password);
}
这样把头文件包含到工程,,
调用InItDBConnPool初始化连接池
然后就可以直接使用接口了
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/andywei1982/archive/2010/02/03/5284815.aspx