注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

VC-Ado数据库连接池  

2013-01-30 18:12:31|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

VC-Ado数据库连接池


一直没有一个比较好的VC中ADO数据连接池的库,想写吧又懒,也没什么时间,所以就一直拖着,头春节了,在看别人的代码,也在看公司的代码,今天有时间把他们整合一下,形成今天的文档。


什么是数据库连接池?他有什么用呢?


举个例子,大家经常会操作数据库ADO去读写数据库的表,好的,如果数据并发少,一次跟着一次,自动形成串行,那么自然就没什么问题了,并且这种情况是大多数的情况下的实际情况。


而有的时候,会有好多个线程或者进程同时读写数据库,这时候儿,如果你的ADO对象被占用了(长时间的大数据量的写),别人就没法子使用了,特别是当你写一个单例的ADO对象时候。当然,有人可以这样说,可以每一个进程或者连接创建一个ADO对象啊,不错,确实是可以的,但是,如果你的线程很多的时候儿,而且他们不是长期的读写,只是交换着频繁读写,比如说,一百个线程,一般同时只会有十个左右的线程会使用ADO对象,那么,你创建很多的ADO对象就浪费了。


这时候,数据库连接池就可以横空出世,他的原理很简单,以上面的例子来说,一百线程,其中既然只有十个在读写,那么完全可以创建十个左右,用完的线程退出后交还给管理数据池的对象,再来一个线程写时,把这个再取出来给他。这样多好。


一般在创建一个数据库访问类时都会类似于下面的方法:(以下例子均为网上资料)


class AdoDB


{


public:


         AdoDB(void);


         ~AdoDB(void);


public:


         BOOL IsEOF();


         BOOL RcordExcute(LPCTSTR strSQL);


         long GetRecordCount();


         BOOL SetCursorLocation(CursorLocationEnum CursorLocation = adUseClient);


         BOOL MoveNext();


         BOOL MoveFirst();


         BOOL MoveLast();


 


         //增删改等函数


         BOOL AddNew();


         BOOL Update();


         void Close();


protected:


         CADODatabase   *m_pDB;


         CADORecordset  *m_pSet;


};


当然可能会有很多的细节需要在这里面添加,这只是一个框架。然后一般会形成一个AdoDB的实例,然后就可以操作数据库了。那连接池就是在外面再套一层,如下:


class CDBPool


{


public:


         struct SDataBase


         {


                   CADODatabase  db;   //ADODB


                   int           iUsed;//标识连接是否在用


                   int           isOk; //标识连接是否成功


         };


         typedef std::list<SDataBase*> SDBList;


public:


         CDBPool();


         ~CDBPool();


         //初始化所有连接


         int InitAllDBConnections(const char*server,


                   const char *dbname,


                   const char*user,


                   const char*passwd,


                   int iMinCn,


                   int iMaxCn=0,


                   long checkInterval=-1


                   );


         //断开所有连接


         void DestroyAllDbConnections();


         //获取一个空闲连接


         SDataBase* GetAConnection(int iRetry=0);


         //交还给连接队列


         int ReleaseAConnection(SDataBase*& pDB);


         CADODatabase* GetDB(SDataBase* pDB);


         //检测是否存在无效连接


         long check();


         //重新连接


         void reConnect();


         //启动守护线程


         void startConnMonitor();


         //停止守护线程


         void stopConnMonitor();


public:      


         long                m_checkInterval;  //检测间隔


         short                            m_shutdownFlag;   //线程启停标志


         //SDataBase        *pDB;


protected:


         int                                 m_iMinCn;         //最小连接数


         int                                 m_iMaxCn;         //最大连接数


         // 数据库信息


         char                    strConnect[1024];


         LPCSTR                      strUsername;      //数据库用户名


         LPCSTR                      strPassword;      //数据库密码


         pthread_t           m_monitorTid;            //守护线程


         bool             m_bInit;          //初始化标志


         SDBList          m_List;           //数据库连接队列


         CRITICAL_SECTION m_ListSection;    //队列保护临界区


private:


         //创建一个连接


         bool InitAConnection(SDataBase &pDB);


         //关闭一个连接


         void CloseAConnection(SDataBase* pDB);


         CDBPool(const CDBPool& rhs){}


         CDBPool& operator=(const CDBPool& rhs){}


};


class DBConnGuard


{


public:


         DBConnGuard(CDBPool& pool,int iRetry=0):m_dbPool(pool)


         {


                   m_pHandle=pool.GetAConnection(iRetry);


                   m_db=pool.GetDB(m_pHandle);


         }


         ~DBConnGuard()


         {       if ( isValid() )


                   {


                            //m_db->RollbackTransaction();


                            m_dbPool.ReleaseAConnection(m_pHandle);


                   }


         }


         operator CADODatabase* ()


         {


                   return m_db;


         }


         CADODatabase*& get_DB()


         {


                   return m_db;


         }


         bool isValid ()


         {


                   return (m_pHandle != NULL);


         }


protected:


         CDBPool& m_dbPool;


         CDBPool::SDataBase* m_pHandle;


         CADODatabase* m_db;


private:


};


或者只控制连接如下:


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);


};     


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();


 


其实这两个基础是一样的,一个是抽象层次高一些,下面这个直接控制连接对象罢了,如果你觉得可以的话,直接将两个整合到一起也是不错的。


这样就可以保证你的实际应用了。


顺道把应用的代码展示一下:


class dbConnection


{


         friend class dbConnectionPool;


         bool           is_using;


public:


         ik_psql::db_conn *conn;


public:


         dbConnection();


         bool isOpen()


         {


                   return (conn->is_connected());


         }


         bool isUsing()


         {


                   return (is_using);


         }          


         void setUsing()


         {


                   is_using = true;


         }


         void releaseUsing()


         {


                   is_using = false;


         }


};


typedef boost::shared_ptr<dbConnection> dbConnectionPtr;


class dbConnectionPool


{   estring                connParam;


         size_t                  maxConnNum;


         std::vector<dbConnectionPtr> vecPool;


         ACE_Thread_Mutex            _PoolMutex;


public:


         dbConnectionPool (): connParam(), maxConnNum(100)


         {


         }


         dbConnectionPtr GetConnection(void);


         void ReleaseConnection (dbConnectionPtr _ptr);


private:


         bool getFreeConnection(dbConnectionPtr &_ptr);


         void replacePoolItem(dbConnectionPtr &_ptr);//此处用来添加,但这个不是一次创建很多,是需要一个创建一个。


};


class IRIS_ATTEND_SERVER_API dbConnectionUser


{


         dbConnectionPool &pool;


public:


         dbConnectionPtr connPtr;


public:


         dbConnectionUser ();


         ik_psql::db_conn *getDbUserConn()


         {


                   return connPtr.get()->conn;


         }


         ~dbConnectionUser(void)


         {


                   pool.ReleaseConnection(connPtr);


         }


};


纸上学来终是浅,绝知此事要躬行。

  评论这张
 
阅读(1670)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017