#ifndef __SAFE_LIST__ #define __SAFE_LIST__ #include #include #include "CritSection.h" class CDatabase; using namespace std; extern void WriteTextLog(const TCHAR *format, ...); template > class SafeList: public std::list<_Ty, _Ax> { public: ThreadSection _critSection; void _push_back(const _Ty& _Val) { AutoThreadSection aSection(&_critSection); push_back(_Val); } void _push_front(const _Ty& _Val) { AutoThreadSection aSection(&_critSection); push_front(_Val); } void _pop_front() { AutoThreadSection aSection(&_critSection); pop_front(); } CDatabase* _pop_front_() { AutoThreadSection aSection(&_critSection); CDatabase* it = front(); pop_front(); return it; } void _pop_back() { AutoThreadSection aSection(&_critSection); pop_back(); } void _remove(const _Ty& _Val_arg) { AutoThreadSection aSection(&_critSection); remove(_Val_arg); } reference _front() { AutoThreadSection aSection(&_critSection); return (*begin()); } const_reference _front() const { AutoThreadSection aSection(&_critSection); return (*begin()); } reference _back() { AutoThreadSection aSection(&_critSection); return (*(--end())); } const_reference _back() const { AutoThreadSection aSection(&_critSection); return (*(--end())); } size_type _size() { //AutoThreadSection aSection(&_critSection); return (_Mysize); } }; typedef SafeList ODBCConnectList; class CODBCPool { ThreadSection m_critSection; // 空闲数据库连接池; ODBCConnectList m_listIdleConnections; // 在使用的数据库连接池; ODBCConnectList m_listBusyConnections; // 可用的指标:最大、最小; INT m_nMaxCount; INT m_nMinCount; // 引入的指针变量; DWORD m_dwDBPort; CString m_strDBSource; CString m_strDBAccount; CString m_strPassWord; CString m_strDBName; BOOL m_bNeedExit; // 退出数据池; BOOL m_bNeedStop; BOOL m_bNeedConnection; public: CODBCPool(void) { m_nRef = 0; m_nObjRef = 0; m_nMaxCount = 0; m_nMinCount = 0; m_bNeedExit = FALSE; m_bNeedStop = FALSE; m_bNeedConnection = FALSE; }; ~CODBCPool(void) {DestroyAllDBConnections();}; // 获取实例指针; static CODBCPool* GetInstance() { static CODBCPool* pInstance = NULL; if ( pInstance == NULL ) pInstance = new CODBCPool; return pInstance; } // 初始化所有连接; DWORD InitializePool( IN LPCTSTR lpDBSource, IN CONST DWORD &dwDBPort, IN LPCTSTR lpDBAccount, IN LPCTSTR lpPassWord, IN LPCTSTR lpDBName, IN CONST INT &nMinConn = 1, IN CONST INT &nMaxConn = 5) { if ( !lpDBSource || lpDBSource[0] == _T('\0') || !lpDBName || lpDBName[0] == _T('\0') ) { return 0; } m_strDBSource = lpDBSource; m_dwDBPort = dwDBPort; m_strDBAccount = lpDBAccount; m_strPassWord = lpPassWord; m_strDBName = lpDBName; m_nMinCount = nMinConn; m_nMaxCount = nMaxConn; return IntiAllConnections(); } // 关闭所有连接; void ReleasePool(){DestroyAllDBConnections();} // 设置数据库信息; void SetDBConnectionInfo(IN LPCTSTR lpDBSource, IN CONST DWORD &dwDBPort, IN LPCTSTR lpDBAccount, IN LPCTSTR lpPassWord, IN LPCTSTR lpDBName); // 初始化所有连接; INT IntiAllConnections() { DestroyAllDBConnections(); // 开始按照最小数量开始创建; int nCount = 0; CDatabase *pDatabase = NULL; for (int i = 0; i < m_nMinCount; i++) { pDatabase = InitAConnection(); if ( pDatabase ) { nCount++; m_listIdleConnections._push_back(pDatabase); InterlockedIncrement(&m_nObjRef); //增加引用计数; pDatabase = NULL; } } return nCount; } // 断开所有连接; void DestroyAllDBConnections() { m_bNeedExit = TRUE; // 首先等待m_listBusyConnections.size() == 0; while(1) { if ( m_listBusyConnections.size() == 0 ) break; Sleep(1000); } ODBCConnectList::iterator itIdle = m_listIdleConnections.begin(); while (itIdle != m_listIdleConnections.end()) { if (NULL != (*itIdle)) { (*itIdle)->Close(); delete (*itIdle); } itIdle = m_listIdleConnections.erase(itIdle); } m_bNeedExit = FALSE; } // 获取一个空闲连接; CDatabase* GetAConnection( IN CONST DWORD &dwTimeOut = 1000 ) { if ( m_bNeedExit )// 停止获取; return NULL; // 1.首先到池中查找有无空闲对象; BOOL bGetIdl = FALSE; DWORD dwTime = GetTickCount(); CDatabase* pDBEngine = NULL; do { if ( m_listIdleConnections._size() > 0){ //AutoThreadSection aSection(&m_critSection); pDBEngine = m_listIdleConnections._pop_front_(); if (pDBEngine) { m_listBusyConnections._push_back(pDBEngine); bGetIdl = TRUE; } } else { if (m_nObjRef < m_nMaxCount) { //AutoThreadSection aSection(&m_critSection); pDBEngine = InitAConnection(); if (pDBEngine){ //bGetIdl = TRUE; m_listBusyConnections._push_back(pDBEngine); InterlockedIncrement(&m_nObjRef); //增加引用计数; WriteTextLog(_T("创建连接对象:共有 %d 个"), m_nObjRef); break; } } } if ( !bGetIdl ) { // 未找到,小憩一会,防止CPU爆满; Sleep(0); // 超时,则结束返回NULL; if ( (GetTickCount() - dwTime) >= dwTimeOut){ WriteTextLog(_T("获取连接对象超时")); break; } } } while ( !bGetIdl ); return pDBEngine; } // 交还连接给空闲队列; void RestoreAConnection(IN CDatabase *pDBEngine) { if ( pDBEngine != NULL ){ m_listBusyConnections._remove(pDBEngine); m_listIdleConnections._push_back(pDBEngine); } } private: volatile LONG m_nRef; volatile LONG m_nObjRef; // 创建一个连接; CDatabase* InitAConnection() { if ( m_nObjRef == m_nMaxCount ) return NULL; CDatabase * pDBEngine = new CDatabase; TCHAR szConnString[MAX_PATH] = {0}; if (m_dwDBPort != 0) { if ( m_strDBAccount.IsEmpty() ) _stprintf_s(szConnString, MAX_PATH, DB_SW_CONN_WITH_PORT, m_strDBSource.GetString(), m_dwDBPort, m_strDBName.GetString()); else _stprintf_s(szConnString, MAX_PATH, DB_SS_CONN_WITH_PORT, m_strDBSource.GetString(), m_dwDBPort, m_strDBName.GetString(), m_strDBAccount.GetString(), m_strPassWord.GetString()); } else { if ( m_strDBAccount.IsEmpty() ) _stprintf_s(szConnString, MAX_PATH, DB_SW_CONN_WITHOUT_PORT, m_strDBSource.GetString(), m_strDBName.GetString()); else _stprintf_s(szConnString, MAX_PATH, DB_SS_CONN_WITHOUT_PORT, m_strDBSource.GetString(), m_strDBName.GetString(), m_strDBAccount.GetString(), m_strPassWord.GetString()); } try { pDBEngine->OpenEx(szConnString, CDatabase::noOdbcDialog); } catch (CDBException* e) { if ( pDBEngine ) delete pDBEngine; pDBEngine = NULL; WriteTextLog(_T("SQL连接串:%s, 返回错误:%s"), szConnString, e->m_strError); } return pDBEngine; } // 关闭一个连接; void CloseAConnection(CDatabase* pDBEngine) { m_listIdleConnections._remove(pDBEngine); InterlockedDecrement(&m_nObjRef); // 减少计数; if ( pDBEngine ) delete pDBEngine; } // 将守卫类友元化; friend class ODBCConnGuard; public: ////////////////////////////////////////////////////////////////////////// // 数据库接口; BOOL ExecuteSQL( IN LPCTSTR lpExcuteSQL, IN CONST DWORD &dwTimeOut = 30000 ); }; #endif // __SAFE_LIST__