在使用ADO的过程中,最理想的操作流程:


程序启动,打开数据库连接,在程序退出前,一直保持这个连接。程序退出时,才关闭该连。

最理想的状态的前提:该数据库连接在中间不会断开。不会由于网络或者数据库服务器的原因导致连接断开。

实际情形是:需要开发一个长时间运行的程序,数据库服务器可能在很远的地方,网络不可靠。人工在连接断开的时候不可能及时的干预。最好的方式就是程序能够检测到连接断开,并且能够自动重新连接。

检测数据库连接断开很简单:在断开的数据库连接对象上执行sql语句或者打开数据集会导致数据异常,捕获该异常时,就可知道数据库连接断开了。

在实际重新连接数据时,出现以下问题:

1. CADODatabase m_Database

对应的数据库连接在程序启动时连接正常,在重连时,先调用Close方法,再调用Open方法,Open方法直接返回成功,在该连接上执行sql语句,出现异常: 未连接到数据库。 这说明: 已经连上数据库对象m_Database在断开连接,重新Open时,不会真正从新打开连接。

2. 如果在同一个线程中,动态创建CADODatabase 对象,用新对象打开链接,同样存在上面的问题。

由于ADO类实际是COM类,考虑COM对象跟线程的关系,采用如下方法实现在连接断开的情况下尝试重新连接。

1. 为每个数据库连接对象 CADODatabase 启动一个线程,作为该COM对象的线程住所。

2. 数据库连接对象 CADODatabase 采用动态创建,即每次创建一个线程,同时创建一个新的CADODatabase对象。

例程:

void CTemplateAppToolDlg::InitDB()
 m_bInitDBThreadExit = false;
 g_ObjInitDBThreadParm.pRunClass = this;
 g_ObjInitDBThreadParm.pRunFun = InitDBFun;
 ::CreateThread(NULL,NULL,ThreadRun,(void*)&g_ObjInitDBThreadParm,0,NULL); 
}void CTemplateAppToolDlg::UnintDB()
 m_bInitDBThreadExit = true;
}void CTemplateAppToolDlg::InitDBFun(void)
 std::string Info; m_DBCenter.SetDBParms(m_DataSource,m_UserID,m_Password);
 m_DBCenter.SetDriverType(m_DBDriverType);
 m_DBCenter.SetTableParms(m_Table,m_Table2); m_bDBInit = false;
 ::CoInitialize(NULL);
 while(true)
  if (m_bInitDBThreadExit)
   m_DBCenter.Uninit();   ::CoUninitialize();
   return ;
  if(m_bDBInit)
  { // 数据库连接已经成功,等待
   Sleep(1000);   continue;
  }  // 
  Info = "连接数据库1...";
  ShowInfo(Info);
  if (! m_DBCenter.Init())
   Info = "数据库1连接失败...";
   ShowInfo(Info);   m_DBInitTimes += 1;
   m_DBCenter.Uninit();
   ::CoUninitialize();
   return;
   Info = "数据库1连接成功...";
   ShowInfo(Info);   m_bDBInit = true;
   m_DBInitTimes += 1;
}

CDBCenter 类:

class CDBCenter
    bool Init();
    void Uninit();    ...
private:
    CADODatabase *m_pDatabase;
bool CDBCenter::Init()
 Uninit(); std::string strConnectString;
 if (m_DBDriverType == DB_DRIVER_MS)
  strConnectString = "Provider=MSDAORA;Data Source=";  
  strConnectString = "Provider=OraOLEDB.Oracle;Data Source="; 
 }  strConnectString += m_strDataSource.c_str();
 strConnectString += ";";
 m_pDatabase = new CADODatabase(); m_pDatabase->SetConnectionTimeout(30);
 BOOL rs;
 rs = m_pDatabase->Open(strConnectString.c_str(),m_strUserID.c_str(),m_strPassword.c_str()); 
 if (rs == FALSE)
  return false; m_pDatabase->m_pConnection->PutCommandTimeout(30);
 std::string strSql = "select * from all_tables where rownum < 2"; bool success = (TRUE == m_pDatabase->Execute(strSql.c_str()));
 TRACE("Init return %d/r/n",success ? "true" : "false");
 return success;
void CDBCenter::Uninit()
 if (m_pDatabase != NULL)
//  m_pDatabase->Close();  delete m_pDatabase;
  m_pDatabase = NULL;
}

主工作线程对数据库连接的重连操作:

void CTemplateAppToolDlg::Process(void)
 m_bProcessRunning = true; std::string Info;
 Info = "工作线程启动...";
 ShowInfo(Info); 
LabCheckDB:
   dbError = false;
      // 通过该数据库连接执行数据库操作
   exist = m_DBCenter.ReadData(value, dbError);   if(dbError)
    Info = "数据库1错误:数据集打开失败...";
    ShowInfo(Info);
   while(dbError)
    if (m_bProcessThreadExit)
     break;
    }    // 数据库1 初始化线程退出 重新初始化
    UnintDB();    Sleep(2000);
    m_bDBInit = false;
    m_bInitDBThreadExit = false;
    m_DBInitTimes = 0;
    // 启动数据库连接线程
    InitDB();
    while(m_DBInitTimes < 1)
     // 尝试一次前 一直等待
     Sleep(1000);
    // 尝试一次 判断是否连上
    if (! m_bDBInit)
     // 没有连上 重新连接
     Sleep(1000);      continue;
    }    // 已经连上,重新执行上面的数据库操作
    goto LabCheckDB;
Source Server         : localhost_3306
Source Server Version : 50719
Source Host           : localhost:3306
Source Database       : oldbo
Target Ser