VC下的ADO连接池

vc利用ado进行多线程的数据库访问 先描述一下我的问题            公司开发一套新的打印服务,其中有多个线程可能同时对数据库进行访问,开始的时候用的是一个数据库连接,但是在多个线程同时访问的时候会报数据库异步访问和一些com异常,之后查阅了一些资料,发现在利用ado在进行多线程的数据库访问的时候,最好每个线程对应一个数据库连接,为了方便对这些链接进行管理,自己写了一个数据库连接池,将源码放到这里和大家分享,共同进步,希望 阅读详情

由于工作需要,查找了很多关于数据库连接池的实现代码.但是发现很多都是JAVA  版本的.我试着改了一下,
代码如下:


/******************************************************************
*
*  ADO 对象的简单封装
*
*******************************************************************/

#ifndef _DATA_BASE_H_
#define _DATA_BASE_H_
#define CATCHERROR(ptr,a) catch(_com_error &e)/
       {/
        ErrorHandler(e,m_ErrStr);/
        ptr=NULL;/
        return a;/
       }

#define CATCHERRGET   catch(_com_error &e)/
       {/
         ErrorHandler(e,m_ErrStr);/
        sprintf(m_ErrStr,"%s/n**For Field Name:%s",m_ErrStr,FieldName);/
        return 0;/
       }

#import "c:/Program Files/Common Files/System/ADO/msado25.tlb" /
              rename("EOF", "EndOfFile")

typedef _RecordsetPtr RecPtr;
typedef _ConnectionPtr CnnPtr;

class Database;
class Table;


class Database
{
public:
 BOOL RollBack();
 BOOL CommitTrans();
 BOOL BeginTrans();
 void Close();
 CnnPtr m_Cnn;
 char m_ErrStr[500];
 Database();
 bool Open(char* UserName, char* Pwd,char* CnnStr);
 bool OpenTbl(int Mode, char* CmdStr, Table& Tbl);
 bool Execute(char* CmdStr, long * lRecordAffected, long Option);
 bool Execute(char* CmdStr, Table& Tbl);
 void GetErrorErrStr(char* ErrStr);
};

class Table{
public:
 int GetBinaryLen(char * FieldName);
 bool GetBinary(char * FieldName, BYTE * pValue);

 BOOL SetPageSize(int size);
 bool Move(int index);
 int GetRecordCount();
 bool Get(char * FieldNam, DWORD & value);
 bool Get(char * FieldName, BYTE * pValue);
 bool Get(char * FieldName, short & value);
 bool Get(char * FieldName, BYTE &value);
 RecPtr m_Rec;
 char m_ErrStr[500];
 int   m_pageSize;

 

 Table();
 void GetErrorErrStr(char* ErrStr);
 int ISEOF();
 HRESULT MoveNext();
 HRESULT MovePrevious();
 bool MoveFirst();
 HRESULT MoveLast();
 /*
 int AddNew();
 int Update();
 int Add(char* FieldName, char* FieldValue);
 int Add(char* FieldName,int FieldValue);
 int Add(char* FieldName,float FieldValue);
 int Add(char* FieldName,double FieldValue);
 int Add(char* FieldName,long FieldValue);
 */
 
 bool Get(char* FieldName, char* FieldValue);
 bool Get(char* FieldName,int& FieldValue);
 bool Get(char* FieldName,float& FieldValue);
 bool Get(char* FieldName,double& FieldValue);
 bool Get(char* FieldName,double& FieldValue,int Scale);
 bool Get(char* FieldName,long& FieldValue);
};

#endif _DATA_BASE_H_

//database.cpp
#include <stdio.h>
#include <iostream.h>
#include <comdef.h>
#include <conio.h>
#include <atlbase.h>
#include "stdafx.h"
#include "Database.h"
#include "htrdserver.h"

_variant_t  vtMissing1(DISP_E_PARAMNOTFOUND, VT_ERROR);

static void ErrorHandler(_com_error &e, char* ErrStr)
{
 
 sprintf(ErrStr,"Error:/n");
 sprintf(ErrStr,"%sCode = %08lx/n",ErrStr ,e.Error());
 sprintf(ErrStr,"%sCode meaning = %s/n", ErrStr, (char*) e.ErrorMessage());
 sprintf(ErrStr,"%sSource = %s/n", ErrStr, (char*) e.Source());
 sprintf(ErrStr,"%sDescription = %s",ErrStr, (char*) e.Description());
}

Database::Database()
{
 m_Cnn=NULL;
 sprintf(m_ErrStr,"NULL POINTER");
}

void Database::GetErrorErrStr(char* ErrStr)
{
 sprintf(ErrStr,"%s",m_ErrStr);
}

void Table::GetErrorErrStr(char* ErrStr)
{
 sprintf(ErrStr,"%s",m_ErrStr);
}

bool Database::Open(char* UserName, char* Pwd,char* CnnStr)
{
 //cnn->Open(strCnn,"sa","sa",NULL);
 try
 {
  HRESULT hr;
  hr    = m_Cnn.CreateInstance( __uuidof( Connection ) );
  m_Cnn->Open(CnnStr, UserName, Pwd, NULL);
 }
 
 CATCHERROR(m_Cnn,0)

 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Database::OpenTbl(int Mode, char* CmdStr, Table &Tbl)
{
 if(m_Cnn==NULL)
 {
  Tbl.m_Rec=NULL;
  sprintf(m_ErrStr,"Invalid Connection");
  return 0;
 }
 RecPtr t_Rec=NULL;
 try
 {
  //t_Rec->putref_ActiveConnection(m_Cnn);
  //vtMissing<<-->>_variant_t((IDispatch *) m_Cnn, true)
  t_Rec.CreateInstance( __uuidof( Recordset ) );
  t_Rec->Open(CmdStr,_variant_t((IDispatch *) m_Cnn, true),adOpenStatic,adLockOptimistic,Mode);
 }
 
 CATCHERROR(Tbl.m_Rec,0)

 Tbl.m_Rec=t_Rec;
 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Database::Execute(char* CmdStr, long * lRecordAffected, long Option)
{
 VARIANT var;
 var.vt = VT_I4;
 try
 {
  m_Cnn->Execute(CmdStr,&var,Option);
  *lRecordAffected = var.lVal;
 }
 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);

  CString str;
  str.Format("数据库执行错误,消息:%s/r/n", m_ErrStr);
  OUTPUT_MSG(str);
  return 0;
 }
 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Database::Execute(char* CmdStr, Table& Tbl)
{
// TRACE(CmdStr);
 int t = strlen(CmdStr);
 RecPtr t_Rec=NULL;
 try
 {
  t_Rec=m_Cnn->Execute(CmdStr,NULL,1);
 }

 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);

  CString str;
  str.Format("数据库执行错误,消息:%s/r/n", m_ErrStr);
  OUTPUT_MSG(str);
  return 0;
 }

 sprintf(m_ErrStr,"Success");
 Tbl.m_Rec=t_Rec;
 sprintf(m_ErrStr,"Success");

 return 1;
}

Table::Table()
{
 m_Rec=NULL;
 m_pageSize = -1;


}

int Table::ISEOF()
{
 int rs;
 if(m_Rec==NULL)
 {
  sprintf(m_ErrStr,"Invalid Record");
  return -1;
 }
 try{
  rs=m_Rec->adoEOF;
 }
 
 CATCHERROR(m_Rec,-2)

 sprintf(m_ErrStr,"Success");
 return rs;
}

bool Table::Get(char* FieldName, char* FieldValue)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   sprintf((char *)FieldValue , "");
   return true;
  }
  VariantChangeType(&vtValue,&vtValue,0, VT_BYREF|VT_BSTR);
  sprintf(FieldValue,"%s",(LPCSTR)((_bstr_t)vtValue.bstrVal));
 }

 CATCHERRGET

 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Table::Get(char* FieldName,int& FieldValue)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  
 
  VariantChangeType(&vtValue,&vtValue,0, VT_I4);
  
  FieldValue=vtValue.intVal;
 }

 CATCHERRGET

 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Table::Get(char* FieldName,float& FieldValue)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   FieldValue = 0;
   return true;
  }
  VariantChangeType(&vtValue,&vtValue,0, VT_R4);
  
  FieldValue=vtValue.fltVal;
 }

 CATCHERRGET

 sprintf(m_ErrStr,"Success");
 return 1;
}

bool Table::Get(char* FieldName,double& FieldValue)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   FieldValue = 0;
   return true;
  }
  
  
  VariantChangeType(&vtValue,&vtValue,0, VT_R8);

  FieldValue = vtValue.dblVal;
  //GetDec(vtValue,FieldValue,3);
 }

 CATCHERRGET
  
  sprintf(m_ErrStr,"Success");
 return 1;
}

HRESULT Table::MoveNext()
{
 HRESULT hr;
 try
 {
  hr=m_Rec->MoveNext();
 }
 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);
  //m_Rec=NULL;
  return -2;
 }
 sprintf(m_ErrStr,"Success");
 return hr;
}

HRESULT Table::MovePrevious()
{
 HRESULT hr;
 try
 {
  hr=m_Rec->MovePrevious();
 }
 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);
  //m_Rec=NULL;
  return -2;
 }
 sprintf(m_ErrStr,"Success");
 return hr;
}

bool Table::MoveFirst()
{
 HRESULT hr;
 try
 {
  hr=m_Rec->MoveFirst();
 }
 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);
  //m_Rec=NULL;
  return false;
 }
 sprintf(m_ErrStr,"Success");
 return true;
}

HRESULT Table::MoveLast()
{
 HRESULT hr;
 try
 {
  hr=m_Rec->MoveLast();
 }
 catch(_com_error &e)
 {
  ErrorHandler(e,m_ErrStr);
  //m_Rec=NULL;
  return -2;
 }
 sprintf(m_ErrStr,"Success");
 return hr;
}

void Database::Close()
{
 try
 {
  m_Cnn = NULL;
 }
 catch (_com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
 }
 
 
}

bool Table::Get(char *FieldName, BYTE &value)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   value = 0;
   return true;
  }
 
  VariantChangeType(&vtValue,&vtValue,0, VT_UI1);
  value=vtValue.bVal;
 }
 
 CATCHERRGET
  
  sprintf(m_ErrStr,"Success");
 return 1;

}

bool Table::Get(char *FieldName, short &value)
{
 
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();

  if (vtValue.vt == VT_NULL)
  {
   value = 0;
   return true;
  }
 
  VariantChangeType(&vtValue,&vtValue,0, VT_I2);
  value=vtValue.iVal;
 }
 
 CATCHERRGET
  
  sprintf(m_ErrStr,"Success");
 return 1;

}

bool Table::Get(char *FieldName, BYTE *pValue)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   sprintf((char *)pValue , "");
   return true;
  }
  VariantChangeType(&vtValue,&vtValue,0, VT_BSTR);
  
  sprintf((char *)pValue,"%s",(LPCSTR)((_bstr_t)vtValue.bstrVal));
 }
 
 CATCHERRGET
  
  sprintf(m_ErrStr,"Success");
 return 1;
}

bool Table::Get(char *FieldName, DWORD &value)
{
 try
 {
  _variant_t  vtValue;
  vtValue = m_Rec->Fields->GetItem(FieldName)->GetValue();
  if (vtValue.vt == VT_NULL)
  {
   value = 0;
   return true;
  }


  VariantChangeType(&vtValue,&vtValue,0, VT_I4);
  
  value = vtValue.lVal;
 }
 
 CATCHERRGET
  
  sprintf(m_ErrStr,"Success");
 return 1;
 

}

int Table::GetRecordCount()
{
 if (m_Rec == NULL)
  return 0;
 
 int ret = 0;
 if (!ISEOF())
  MoveFirst();
 
 while(!ISEOF())
 {
  ret++;
  MoveNext();
 }
 
 return ret;
}

bool Table::Move(int index)
{
 if (index == 0)
  return true;
 
 try
 {
  m_Rec->Move(index);
 }
 catch (_com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
 }
 
  sprintf(m_ErrStr,"Success");
 return 1;
}


BOOL Database::BeginTrans()
{
 
 if (m_Cnn == NULL)
  return FALSE;

 try
 {
  m_Cnn->BeginTrans();
 }
 catch(_com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
  return FALSE;
 }
 return TRUE;
}

BOOL Database::CommitTrans()
{
 if (m_Cnn == NULL)
  return FALSE;
 try
 {
  m_Cnn->CommitTrans();
 }
 catch(_com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
  return FALSE;
 }
 return TRUE;
}

BOOL Table::SetPageSize(int size)
{
 if (m_Rec == NULL)
  return FALSE;
 if (GetRecordCount() < size)
  return FALSE;
 
 m_pageSize = size;
 
 return TRUE;
}

 

BOOL Database::RollBack()
{
 if (m_Cnn == NULL)
  return FALSE;
 try
 {
  m_Cnn->RollbackTrans();
 }
 catch(_com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
  return FALSE;
 }
 return TRUE;
}

/*
 *   purpose:  get the binary filed value from data base
 *    the memory of pValue must be allocated by the user.
 *    the length of pValue is known as before.
 */
bool Table::GetBinary(char *FieldName, BYTE *pValue)
{
 HRESULT hr = -1;
 try
 {
  _StreamPtr   m_pStream;
 
  hr = m_pStream.CreateInstance(__uuidof(Stream));
  m_pStream->PutType(adTypeBinary);
  
  _variant_t vtEmpty (DISP_E_PARAMNOTFOUND, VT_ERROR);
  _bstr_t bstrEmpty(L"");
  
  hr = m_pStream->Open(vtEmpty,adModeUnknown,adOpenStreamUnspecified,
   bstrEmpty, bstrEmpty);

  hr = m_pStream->Write(m_Rec->Fields->GetItem(FieldName)->Value);
  m_pStream->Position = 0;

  _variant_t var(m_pStream->Read(adReadAll));
  LONG lDataLength = m_pStream->GetSize();

  BYTE * pBuff= (BYTE *)GlobalAlloc(GMEM_FIXED, lDataLength);
  
  if(var.vt == (VT_ARRAY | VT_UI1))
  {
   HRESULT hr = -1;
   hr = SafeArrayAccessData(var.parray, (void **)&pBuff);

   memcpy(pValue, pBuff, lDataLength);

   GlobalFree((HGLOBAL)pBuff);
  }
  else
  {
   GlobalFree((HGLOBAL)pBuff);
   return false;
  }

  m_pStream->Close();

 }
 catch ( _com_error e)
 {
  LPCTSTR lpsz = e.ErrorMessage();
  if (hr == 0)
   return true;
  else
   return false;

 }

 return true;
 
}

int Table::GetBinaryLen(char *FieldName)
{
 int nRet = 0;
 try
 {
  nRet = m_Rec->Fields->GetItem(FieldName)->ActualSize;
 }
 catch(_com_error e)
 {
  nRet = 0;
 }

 return nRet;
}

// ConnObject.h: interface for the CConnObject class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CONNOBJECT_H__2818382C_8737_44D0_B319_1032C614EFEE__INCLUDED_)
#define AFX_CONNOBJECT_H__2818382C_8737_44D0_B319_1032C614EFEE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Database.h"

class CConnPool;

class CConnObject
{
public:
 CConnObject(CConnPool *  pool)
 {
  ASSERT(pool);
  pPool = pool;
 // conn = NULL;
  m_bInUse = FALSE;
  m_nLastEnd = 0;
  m_nLastBegin = 0;
  m_nUseCount   = 0;
  m_nTotalUseTime = 0;
 }
 ~CConnObject();
 // 用完本身不能关闭,交给连接池处理
 


public:
 //释放连接对象给连接池
 void Close();

 Database          conn;
 BOOL     m_bInUse;
 int      m_nLastEnd;   //最后一次使用结束时间
 int      m_nLastBegin;    //最后一次开始时间
 int      m_nUseCount;     //使用次数
 CConnPool *       pPool;
 int      m_nTotalUseTime;

public:

 //得到总得使用时间
 int  GetTotalUseTime()
 {
  return m_nTotalUseTime;
 }
};
CConnObject::~CConnObject()
{

}

void CConnObject::Close()
{
 m_nTotalUseTime += GetTickCount() - m_nLastBegin;
 pPool->Close(this);
}

#endif //
// ConnPool.h: interface for the CConnPool class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_)
#define AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
 
#include <atlbase.h>

#include "ConnObject.h"
 
/***************************************
数据库连接池.
一个连接池对应于一个库
****************************************/

/*

*/
class CConnPool 
{
public:
 void OnTimer();
 static void __stdcall TimerProc(HWND hWnd, UINT msg, UINT id, DWORD dwTime);

 //得到一个连接
 CConnObject * GetConnect();
 //释放一个连接回连接池
 void Close(CConnObject * pConn);
 //销毁连接池
 void Destroy();
 //创建连接池  strConn: 连接串
 BOOL Init(CString strConn);

 CConnPool();
 virtual ~CConnPool();


public:

 UINT        m_nTimer;     //定时器
 
 CSimpleArray<CConnObject *>      m_listConn;   //连接链表

 UINT        m_nTimeOut;   //连接最大空闲时间
 UINT        m_ConnMax;    //连接数量上限
 UINT        m_ConnMin;    //连接数量下限
 UINT        m_nMaxCount;  //连接最大使用次数
 UINT        m_nMaxUseTime; //最大使用时间
 CString        m_strConn;    //连接串

 HANDLE                 m_cs;   //保证改变连接池状态时代码不终端

protected:

 //创建一个新的连接
 CConnObject * CreateNewConn();
};

#endif // !defined(AFX_CONNPOOL_H__FD09CC72_3241_4A82_912F_06F92BE1CD54__INCLUDED_)
// ConnPool.cpp: implementation of the CConnPool class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "HTRDServer.h"
#include "ConnPool.h"
#include "const_def.h"
#include "MyEvent.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


CConnPool::CConnPool()
{

 m_ConnMin = CONN_MIN;
 m_nTimeOut = CONN_TIMEOUT;
 m_nMaxUseTime = CONN_MAX_USETIME;
 m_nMaxCount  =  500;

 m_cs = CreateEvent(NULL, TRUE, TRUE, "da8b4c9d-e4ef-4c9a-a6d2-941ee98400d2");

}

CConnPool::~CConnPool()
{
 Destroy();
 
}

BOOL CConnPool::Init(CString strConn)
{
 m_ConnMax = theApp.m_sysSetting.m_nConnCount;

 m_strConn = strConn;
 for (UINT i = 0;i < m_ConnMax; i++)
 {
  CConnObject * pObj = CreateNewConn();
  if (!pObj)
   return FALSE;
  m_listConn.Add(pObj);
 }
 
 return TRUE;

 //启动连接池维护计时器
// m_nTimer = SetTimer(0, 0, CONNPOOL_TIMER, (TIMERPROC)TimerProc);

}

void CConnPool::Destroy()
{
 for (int i = 0;i < m_listConn.GetSize(); i++)
 {
  m_listConn[i]->m_bInUse = FALSE;

   m_listConn[i]->conn.Close();
 // m_listConn[i]->conn->Release();

  delete   m_listConn[i];
 }

 m_listConn.RemoveAll();

 KillTimer(NULL, m_nTimer);
}
/*
 * 释放连接时需要保护数据一致性,所以使用 临界对象
 */
void CConnPool::Close(CConnObject *pConn)
{
 
 //回收!

 CMyEvent cs(m_cs);

 for (int i = 0;i < m_listConn.GetSize(); i++)
 {
  if (m_listConn[i] == pConn)
  {
   m_listConn[i]->m_bInUse = FALSE;
   m_listConn[i]->m_nUseCount++;
   m_listConn[i]->m_nLastEnd = ::GetTickCount();

   //判断使用次数是否过多,使用时间是否过多
   //如果过度使用该连接,则重新创建
   if (m_listConn[i]->m_nUseCount > (int)m_nMaxCount ||
    m_listConn[i]->GetTotalUseTime() > CONN_MAX_USETIME)
   {
    OUTPUT_MSG("有数据库连接对象使用过多,需要重新连接/r/n");
    
    m_listConn[i]->conn.Close();
    if (!m_listConn[i]->conn.Open("", "", m_strConn.GetBuffer(0)))
    {
     AfxMessageBox("重新数据库连接对象出错!, 系统退出!");
     ExitProcess(0);
    }
    m_listConn[i]->m_nLastBegin = 0;
    m_listConn[i]->m_nLastEnd = 0;
    m_listConn[i]->m_nTotalUseTime = 0;
    m_listConn[i]->m_nUseCount = 0;

   }
   
   return;
  }
   
 }


#ifdef _DEBUG
 AfxMessageBox("The connect object is no mine!");
#endif

}
/*
 * 得到连接时需要保护数据一致性,所以使用 临界对象
 */
CConnObject * CConnPool::GetConnect()
{
 CMyEvent cs(m_cs);

 CConnObject * pObj = NULL;
 for (int i = 0;i < m_listConn.GetSize(); i++)
 {
  if (!m_listConn[i]->m_bInUse)
  {
   m_listConn[i]->m_bInUse = TRUE;
   pObj = m_listConn[i];
   pObj->m_nLastBegin = ::GetTickCount();
   
   return pObj;
  }
   
 }

 if ((pObj == NULL) &&
  (m_listConn.GetSize() < (int)m_ConnMax)) //connect object is no enough!
 {
  pObj = CreateNewConn();
  pObj->m_bInUse = TRUE;
  m_listConn.Add(pObj);
  return pObj;
 }


 //连接池已经满载!
 return NULL;
}

CConnObject * CConnPool::CreateNewConn()
{
 CConnObject * pConn = new CConnObject(this);
 
 
 if (!pConn->conn.Open("","",_bstr_t(m_strConn)))
  return NULL;
 
 
 return pConn;
}

void CConnPool::TimerProc(HWND hWnd, UINT msg, UINT id, DWORD dwTime)
{
// CHTRDServerApp * pApp = (CHTRDServerApp *)AfxGetApp();
// ASSERT(pPool);

// pPool->OnTimer();
 
}

/*
 * 调度连接池
 */
void CConnPool::OnTimer()
{ 
 
 DWORD dwTime = ::GetTickCount();
 for (int i = 0; i < m_listConn.GetSize(); i++)
 {
  if (m_listConn[i]->conn.m_Cnn->State == adStateClosed)
  {
   //delete from pool
   delete m_listConn[i];
   m_listConn.RemoveAt(i);
   TRACE("One conn closed!, delete from pool!/n");
  }
  else if (!m_listConn[i]->m_bInUse)
  {
   if (dwTime - m_listConn[i]->m_nLastEnd >= m_nTimeOut)
   {
    m_listConn[i]->conn.Close();
    delete m_listConn[i];
    m_listConn.RemoveAt(i);
    TRACE("One conn time out!/n");
   }
   else if (m_listConn[i]->m_nUseCount >= (int)m_nMaxCount)
   {
    m_listConn[i]->conn.Close();
    delete m_listConn[i];
    m_listConn.RemoveAt(i);
    TRACE("One conn use to much!/n");

   }
  }
  else if (m_listConn[i]->GetTotalUseTime() >= (int)m_nMaxUseTime)
  {
   m_listConn[i]->conn.Close();
   delete m_listConn[i];
   m_listConn.RemoveAt(i);

   TRACE("One conn use too long/n");
  }
 }

 //检查连接数,小于下限则添加到下限
 for (i = m_listConn.GetSize(); i < (int)m_ConnMin;i++)
 {
  CConnObject * pObj = CreateNewConn();
  ASSERT(pObj);
  m_listConn.Add(pObj);
 }
 
}




VC6.0环境下使用ADO连接Oracle数据库的详细步骤 在现代的IT行业中,数据访问技术是构建动态Web应用和业务系统的核心组件之一。ADO(ActiveX Data Objects)作为一种轻量级的数据访问接口,已经被广泛应用于多种编程语言和开发环境中,用来实现应用程序与数据库之间的连接和交互。ADO的出现简化了数据访问的过程,让开发者能够以较少的代码实现复杂的数据操作。 阅读详情

相关推荐

VC6.0与SQL Server 2008数据库交互实践

VC6.0与SQL Server 2008的连接通常有多种方法,其中ODBC和ADO是两种常用且强大的技术。ODBC是一种提供统一访问各种数据库的标准编程接口,而ADO提供了面向对象的编程模型。本章将重点介绍这两种连接方式的基本步骤与技巧,帮助开发者快速搭建起应用程序与数据库之间的桥梁。开放数据库连接(ODBC)是一种在不同数据库之间进行通信的标准应用程序接口(API)。它由微软公司于1990年推出,旨在提供一种统一的方法来访问多种数据库管理系统(DBMS)。

weixin_42604188的博客 969

MFC用ADO方式连接数据库,断线重连的问题,如何恢复数据库链接

采用的方式是用定时器不断查询数据库连接状态, void CSqlDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default if(nIDEvent==TIMER_SQL) { //检查SQL m_...

weixin_30466953的博客 449

VC下运用ADO连接池例子

注意在sql中建立个表Table_1 名字users 小菜鸟做的 高手达人就不用来笑了

ADO断网重连

在catch() {   }中断开con

芒果儿 1648

VC++数据库连接池例子

VC++数据库连接池例子VC++数据库连接池例子VC++数据库连接池例子VC++数据库连接池例子VC++数据库连接池例子

vc 数据库连接池

用vs2008开发的数据库连接池,建立了一个连接队列,并且有一个守护线程进行监督,当发现无效连接和使用过的连接则进行删除。本连接池调用的ado库是进行封装过的ado库,调用的线程库也是进行封装过的动态链接库,希望对大家有帮助,并及时反馈连接池考虑的不足之处。

ADO 数据库连接断开重连

     在使用ADO的过程中,最理想的操作流程: <br />    程序启动,打开数据库连接,在程序退出前,一直保持这个连接。程序退出时,才关闭该连。<br />    最理想的状态的前提:该数据库连接在中间不会断开。不会由于网络或者数据库服务器的原因导致连接断开。<br />    <br />    实际情形是:需要开发一个长时间运行的程序,数据库服务器可能在很远的地方,网络不可靠。人工在连接断开的时候不可能及时的干预。最好的方式就是程序能够检测到连接断开,并且能够自动重新连接。<br />    

edward的专栏 8657

VC数据库连接池,提供VC的朋友参考

VC数据库连接池VC数据库连接池VC数据库连接池

VC++调用带参数的存储过程

最近由于工作之需,要利用VC进行一些高级的数据库操作,如执行存储过程等。遍寻网络资源发现好使的不多(经常#30XX错误,大部分应该是COM的VARIANT数据类型所致,其实有个讨巧的方法,请看下文),在自己的实验下小有所得。记下学习笔记以备参考:1 进行ADO编程的必备步骤:引入msado15.dll #import "c:/program files/common files/syste

aa211314的专栏 6622

ado连接池实例

Delphi TThread中文注释2009-10-22 16:58TThread是一个抽象类,可以创建几个独立的线程。 类关系 TObject 在一个多线程的应用程序中创建一个TThread的后子类代表一个线程。每一新子类的TThread对象的实例是一个新的线程。从TThread派生的多线程实例可以构成Delphi的多线程应用程序。    当一个应用程序运行时,应用程序就被载入内存准备执行。此时,它成为包含一个或多个线程的进程,每个线程含有数据、代码和系统资源。线程执行应用程序的部分内容,并由系统分配CPU时间。同一进程的所有线程共享同一地址空间,可以访问进程的全局变量。线程通过以下工作改善应用的性能:管理多通信设备的输入。    区分任务的优先级。优先级高的处理紧急的任务。优先级低的处理其他任务。    以下是使用线程的一些建议:    同时跟踪太多的线程消耗CPU时间。对单处理器系统,一个进程最多有16个线程。    当多个线程更新相同的资源时,应使线程同步以避免冲突。    大多数访问VCL对象和更新窗体的方法必须从主VCL线程内部调用。    以下为创建和使用一个新线程的过程:    (1)单击File|New|Thread菜单项,创建一个包含对象的新单元,该对象源于TThread类。    (2)定义新线程对象和Create方法。    (3)通过插入线程执行时需要的代码定义线程对象和Execute方法。    (4)将使用VCL组件的任何调用传递给Synchronize方法,以避免多线程冲突。

Kill5.37版本下,使用ARMcomplier6编译__asm 函数报错的问题

Kill5-5.37版本下,使用ARMcomplier6编译__asm 函数报错的问题 问题简要描述: 昨日更新了keil5软件的版本,从5.17更新到了5.37版本,然后编译STM32项目文件时,软件提示编译报错。报错问题如下: Build started: Project: QKsoftware *** Using Compiler 'V6.18', folder: 'E:\MDK-ARM\ARM\ARM\ARMCLANG\Bin' Build target 'QKsoftware' compiling

weixin_43644424的博客 1万+

VC+ADO断开后重连的检测与实现

最近使用VC6开发程序连接SQL Server数据库,使用的是codeproject.com上面的一个ADO类,地址如下: http://www.codeproject.com/Articles/1075/A-set-of-ADO-classes-version-2-20 类库很好用,大部分功能都已封装进去,直接调用即可。最近测试应用程序发现在网络故障(网线断开,网卡、交换机故障等)情况下

shengfang666的专栏 2388

上证指数30年k线图_金融占星简单解读上证指数30年历史行情

阅读此文需要一定的占星基础知识,本人对于金融知识了解甚少,如有描述错误请包涵指正!影响大众事件发展趋势的都是外行星,即木星-冥王星这5颗,由于时间跨度长达30年,绘制社会行星的K线图工作量太大,所以只以时代行星对这30年行情的简单解读作为分享,在今后的短期分析中会逐渐加入社会行星,甚至在个股分析上还会加入个人行星。那即使只绘制时代行星,所展现出来的信息也无法在一张图上画出来,否则太乱难以分辨,所以...

weixin_39831242的博客 1674

ado + vc + 连接池(转)

/********************************************************************  ADO 对象的简单封装********************************************************************/#ifndef _DATA_BASE_H_#define _DATA_BASE_H_#defi

zp752963831的专栏 1577

Hadoop实战:用MapReduce分析YouTube视频数据集(附完整代码)

本文提供了一个完整的Hadoop MapReduce实战教程,指导读者使用MapReduce框架分析YouTube视频数据集,统计不同视频类别的数量分布。教程涵盖从数据获取、预处理、HDFS操作到Java代码编写、作业提交及结果可视化的全流程,并附有完整代码,帮助开发者深入理解分布式计算思想。

lilh34434的博客 198

基于springboot生鲜食品订购系统的设计与实现

近年来互联网络的迅猛发展和电子终端设备的普及,赋予了各行业充足的发展空间。微信小程序的O2O生鲜食品订购相比于传统信息技术,时效性是它最大的特色,已经在电子娱乐、经济等中发挥着举足轻重的作用。短时间内迅速扩大了线上管理系统的规模。尽管O2O生鲜食品订购已经有了很大程度的发展,但在微信小程序的O2O生鲜食品订购领域上却少有建设。

1024

vc mysql 连接池_VCDBConnectionPool 很好用的VC数据库连接池,网上太难找了,大家参照一下 ADO...

VCDBConnectionPool下载开发工具: Visual C++文件大小: 379 KB上传时间: 2010-10-16下载次数: 95提 供 者: harry详细说明:很好用的VC数据库连接池,网上太难找了,大家参照一下-Good use of the VC database connection pool, we consult a文件列表(点击判断是否您需要的文件,如果是垃圾请在下面...

weixin_42109639的博客 204

Supervisor 安装与使用

一、Supervisor 介绍 Supervisor 是一个用 Python 编写的进程管理工具,它可以用于监控和控制类 UNIX 操作系统上的多个进程。它是一个客户端/服务器系统,其中 Supervisor 的服务器端称为 supervisord,负责启动管理的子进程、响应客户端命令、重启崩溃或退出的子进程、记录子进程的 stdout 和 stderr 输出,以及处理子进程生命周期中的事件。客...

疯子丶pony的博客 3863

一种利用ADO连接池操作MySQL的解决方案(VC++)

VC++连接MySQL数据库 常用的方式有三种:ADO、mysql++,mysql API ; 本文只讲述ADO的连接方式。 为什么要使用连接池? 对于简单的数据库应用,完全可以先创建一个常连接(此连接永远不关闭,直接数进程退出),但是这样做至少会引起两个问题:(1)资源竞争,多个数据库请求操作不能同时进行,后一请求必须要等到前一请求完成后才能进行;(2)多线程情况下容易出现混乱,...

weixin_30510153的博客 183

【AUTOSAR-IpduM】-2.2-创建并配置一个接收RX的(Multiplexed-I-PDU)多路复用

案列背景: 在CFG中配置一个发送TX的(Multiplexed-I-PDU)多路复用Frame。 目录 1 在Arxml中创建一个发送的多路复用Frame 2 CFG导入带多路复用Frame的ARXML 2.1 CFG中提示的错误Error 2.2 如何解决CFG中提示的错误Error 3 结尾 <--返回「Autosar_BSW高阶配置」总目录--> <--返回「Autosar_BSW高阶配置」专栏主页--> <--返回「个人博客」首页--&g..

「汽车电子助手」的博客 1569

33、AI赋能5G/6G通信:LDPC码解码与强化学习技术解析

本文探讨了基于AI和强化学习的LDPC码技术在5G/6G通信中的应用。包括LAMS解码器、神经MS解码器、盲识别方法、统一极性-LDPC解码器、NNMS和SNNMS解码器、N-2D-NMS解码器、神经分层MS解码器、MAB-NS方案以及强化学习与MCTS结合的技术。这些技术在提升解码性能、降低计算复杂度和增强系统适应性方面表现出色,为未来通信系统的发展提供了强有力的支持。

lambda的博客 242

利用ado连接mysql_一种利用ADO连接池操作MySQL的解决方案(VC++)

1 //==================头文件 =====================//2 //定义数据库连结基本信息结构3 typedef struct4 {5 char db_ip[20]; //ip地址6 uint32 db_port; //端口7 char db_user[20];//用户8 char db_pwd[32];...

weixin_29092787的博客 261

本地搭建 GitLab 14.1.0版本CI/CD

GitLab 镜像版本 gitlab/gitlab-ce:14.1.0-ce.0 GitLab Runner 镜像版本 gitlab/gitlab-runner:v14.1.0 搭建此套环境是在一台32G的windows电脑上安装的。 使用dokcer安装。 此外还涉及的软件Docker Desktop,WSL 安装GitLab 首先启动 dockcer,打开WSL 打开后 首先定义GitLab的持久化目录 export GITLAB_HOME=/srv/gitlab 然后运行安装GitLab的命令

知无涯 4491

数据库连接池的设计考虑 选择自 vcbear 的 Blog

周末检到本J2EE的书翻了两下(1200多页,我靠),其中有提到JDBC的连接池,小有兴趣,因为我的VC-ADO程序也可以考虑实现个简单连接池来用用。ADO的连接有几个特点:1.它不是线程安全的。容易造成事务死锁。一般单条sql的不会死锁,但比如执行事务或游标时就很容易死锁掉.所以一般的多线程程序不提倡重用同一个ADO Connection2:ADO会自己管理OLEDB连接池,当调用Conne

henry的专栏 1524

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

VC中如何使用ADO

1。首先,我们必须建立一个VC的工程。建立VC工程很简单,只要如下操作即可。    1. 运行VC,菜单->File->New->Projects,然后选择MFC AppWizard(exe),然后填好工程名称,点击OK。    2. 选择应用程序类型为Dialog based。    3. 点击Finish,完成。 2。导入ADO。在VC环境下,一般来说,我们都是用的ADO来连接数据库的

月光秦王 504

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

xiaoly_caep
博客等级 码龄22年 1粉丝 1原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值