博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在LINUX下用C/C++写了一个连接池(访问MYSQL)的类

Posted on 2012-02-25 17:32  容容乃大  阅读(3322)  评论(0)    收藏  举报

一、头文件【存为:connPool.h】

#ifndef __CONNECTION_POOL_H__
#define __CONNECTION_POOL_H__

#include "mutex.h"


#define  MYSQL_CONN_NUM_MAX_VALUE   500
using namespace std;

enum _USE_STATUS
{
   US_USE = 0,
   US_IDLE = 1
};

typedef  struct _sConStatus
{
   void*  connAddr;
   int    useStatus;
}sConStatus;


class CConnPool
{
public:
    CConnPool();
    ~CConnPool();
public:
    int Init(string& strMysqlIp, string&  strUser, string&  strPwd, string&  strDbName, int nMysqlPort, int nConnNum);//connection  pool init
    void* getOneConn();//get a connection
    void  retOneConn(void* pMysql);// return a connection
    void  checkConn(); // check the connection if is alive
   
    void* createOneConn();
   
public:

   char m_szMysqlIp[100];
   char m_szUser[100];
   char m_szPwd[100];
   char m_szDbName[100];
   int  m_nMysqlPort;  
   int  m_nConnNum;
     
public:
    CMutex  m_sMutex;
    vector<void*>  m_vectorConn;
    map<void*, int> m_mapVI;
    map<void*, void*> m_mapMysqlScs;
   
};


 
class CConnPoolV2
{
public:
    CConnPoolV2();
    ~CConnPoolV2();
public:
    int Init(string& strMysqlIp, string&  strUser, string&  strPwd, string&  strDbName, int nMysqlPort, int nConnNum);//connection  pool init
    void* getOneConn(); //从连接池取一个连接
    void  retOneConn(void* pConn);// 连接用完了,把它放回连接池。以便其他人用。
    void  checkConn(); // check the connection if is alive
   
    void* createOneConn();
   
private:
   string m_strMysqlIp;
   string m_strUser;
   string m_strPwd;
   string m_strDbName;
   int  m_nMysqlPort; 
   int  m_nConnNum;
     
private:
    CMutex  m_sMutex;
    vector<void*>  m_vectorConn;
    map<void*, int> m_mapVI; //  从连接的地址,快速找到索引,便于存放到m_vectorConn中。
  
};
 

#endif

 

二、源码【存为:connPool.cpp】

 

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <time.h> 
#include <iostream>                      
#include <memory>
#include <string>
#include <map>
#include <vector>

#include "mysql.h"
#include "encapsulation_mysql.h"
#include "connPool.h"
#include "mutex.h"

 

using namespace std;
using namespace EncapMysql;


CConnPool::CConnPool( )
{
}

CConnPool::~CConnPool( )
{
}

void* CConnPool::createOneConn()
{
     MYSQL*  mysql;
     mysql = mysql_init(0);
     if(mysql == NULL)
     {
    cout << "mysql_init fail**" << endl;     
    return NULL;
     }
 
     if(mysql_real_connect(mysql,  m_szMysqlIp , m_szUser ,   m_szPwd,    m_szDbName  m_nMysqlPort, NULL,0)==NULL)
     {
     cout << "connect failure!" << endl;
     return NULL;
   }
     else
     {
    cout << "connect success!" << endl;
     }
     //
     return mysql;
 
}

int CConnPool::Init(string& strMysqlIp, string&  strUser, string&  strPwd, string&  strDbName, int nMysqlPort, int nConnNum)
{
 
    strcpy(m_szMysqlIp, strMysqlIp.c_str());
    strcpy( m_szUser, strUser.c_str());
    strcpy(m_szPwd, strPwd.c_str());
    strcpy(m_szDbName, strDbName.c_str());
    m_nMysqlPort = nMysqlPort;  
   m_nConnNum = nConnNum; 
  
    MYSQL*  mysql;
   
    for(int i=0; i<nConnNum; i++)
    {
       mysql = (MYSQL*)this->createOneConn();
       if(mysql == NULL)
        return -1;
       // 
      sConStatus* scs = new sConStatus();
      scs->connAddr = mysql;
      scs->useStatus = US_IDLE;
      m_vectorConn.push_back(scs); 
      m_mapVI[scs] = i;
      m_mapMysqlScs[mysql] = scs;
  }
  
  m_nConnNum = nConnNum;
}

//从连接池中取一个连接,同时,给它做一个标记,表明它已经被使用,防止别的线程再使用。
void* CConnPool::getOneConn()
{
    int N = m_vectorConn.size();
  for(int i=0; i< N; i++)
  {
      CGuard  guard(m_sMutex);
      sConStatus* scs = (sConStatus*)m_vectorConn[i];
        if(scs->useStatus ==  US_IDLE)
        {
           scs->useStatus = US_USE;
          return  scs->connAddr;
       
  }
  //
  return NULL;
}

//把连接归还给连接池。同时,给它做一个标记,表明它是空闲的,可以使用。
void  CConnPool::retOneConn(void* pMysql)
{
  if(!pMysql)
    return;
  // 
  map<void*, void*>::iterator  it1;
  map<void*, int>::iterator it2;
 
  CGuard  guard(m_sMutex);
 
  it1 = m_mapMysqlScs.find(pMysql);
  if(it1 == m_mapMysqlScs.end())
      return;
  it2 = m_mapVI.find(it1->second);
  if(it2 == m_mapVI.end())
      return;
  int nInx = it2->second;

  sConStatus* scs = (sConStatus*) m_vectorConn[nInx];
  scs->useStatus = US_IDLE;
  
}


void  CConnPool::checkConn()
{
   map<void*, void*>::iterator  it1;
   MYSQL*  mysql;
   // 
    for(int i=0; i<m_nConnNum ; i++)
    {
     CGuard  guard(m_sMutex);
     sConStatus* scs = (sConStatus*)m_vectorConn[i];
     if(scs->useStatus == US_USE)
         continue;
     //   
     mysql =(MYSQL*)(scs->connAddr);
     int status=mysql_query(mysql, "select count(*) from t_user;" );
    if(status != 0) //说明连接已经不可用了。
    {
        it1 = m_mapMysqlScs.find(mysql);
      if(it1 != m_mapMysqlScs.end())
       {
          m_mapMysqlScs.erase(it1);
       }
      //
        mysql_close(mysql);
        //
        mysql = (MYSQL*)this->createOneConn();
      m_mapMysqlScs[mysql] = scs;
    }
    }
    //
}

 
////////////////////////////// 2011-01-20, 这个类这样写,感觉耦合性更为松散,比较好。使用起来也好理解一些。
CConnPoolV2::CConnPoolV2( )
{
}

CConnPoolV2::~CConnPoolV2( )
{
}

//创建一个连接,并设为 IDLE状态。
void* CConnPoolV2::createOneConn()
{
   try
   {
     CEncapMysql*  pEM = new CEncapMysql();
     if(pEM == NULL)
     {
      printf("pEM == NULL**\r\n"); 
      return NULL;
      
     //
     int nRet = pEM->Connect(m_strMysqlIp.c_str(), m_strUser.c_str(), m_strPwd.c_str());
     if(nRet != 0)
     {
      printf("pEM->Connect fail**\r\n"); 
      return NULL;
            
        //      
      pEM->SetIdle();
     //
     return pEM;
   
  catch(...)
  {
     printf("createOneConn  exception**\r\n"); 
     return NULL;
  }
}

//成功: 返回0
int CConnPoolV2::Init(string& strMysqlIp, string&  strUser, string&  strPwd, string&  strDbName, int nMysqlPort, int nConnNum)
{
 
    m_strMysqlIp  = strMysqlIp;
    m_strUser     = strUser;
    m_strPwd      = strPwd;
    m_strDbName   = strDbName;
    m_nMysqlPort = nMysqlPort;  
   m_nConnNum = nConnNum; 
  
    CEncapMysql* pEM;
    int nRet;
    for(int i=0; i<nConnNum; i++)
    {
       pEM = (CEncapMysql*)this->createOneConn();
        if(!pEM )
          return -1;
       // 
      m_vectorConn.push_back(pEM); 
      m_mapVI[pEM] = i;
  }
  
  return  0;
}


void* CConnPoolV2::getOneConn()
{
    CGuard  guard(m_sMutex);
    //
  for(int i=0; i< m_nConnNum; i++)
  {

      CEncapMysql* pEM = (CEncapMysql*)m_vectorConn[i];
        if( pEM->IsIdle())
        {
           pEM->SetUsed();
          return pEM;
       
  }
  //可能访问MYSQL的用户较多,连接池中已无空闲连接了。只要总连接数没有超限,就新建一个连接。
  if(m_nConnNum < MYSQL_CONN_NUM_MAX_VALUE)
  {
     CEncapMysql* pEM = (CEncapMysql*)this->createOneConn();
        if(!pEM )
          return NULL;
       // 
      m_vectorConn.push_back(pEM); 
      m_mapVI[pEM] = m_nConnNum++;
  
  //
  return NULL;
}

void  CConnPoolV2::retOneConn(void* pConn)
{
  map<void*, int>::iterator it;
 
  CGuard  guard(m_sMutex);

  it = m_mapVI.find(pConn);
  if(it == m_mapVI.end())
  {
      printf("retOneConn  fail***\n"); 
      return;
   
  int nInx = it->second;

  CEncapMysql* pEM = (CEncapMysql*) m_vectorConn[nInx];
  pEM->SetIdle();

   printf("retOneConn  succ!\n"); 
}


void  CConnPoolV2::checkConn()
{
   
    //暂时可以不实现。因为查询失败时,已重新连接了。
}