ADO编程详解(C++)
一、概述
?ADO即Microsoft ActiveXData Object,是Microsoft繼ODBC之后,基于OLE DB技術的一種數據庫操作技術,使您能夠編寫通過?OLE DB?提供者對在數據庫服務器中的數據進行訪問和操作的應用程序。ADO同OLE DB、數據庫之間的關系可以用下圖來表示:
?其主要優點是易于使用、高速度、低內存支出和占用磁盤空間較少。ADO?支持用于建立基于客戶端/服務器和?Web?的應用程序的主要功能。
二、ADO初步認識
?在此介紹的ADO編程技術都是基于C++的,要熟練掌握如何用ADO操作數據庫,首先對ADO技術得有個總體的了解,AD0主要由幾個對象組成:Connection、Command、Paramenter、Recorderset、Fields、Error、Property對象,對數據庫的操作,都是通過這幾個對象來進行的,對象模型的關系圖如下:
?2.1 Connection對象
在數據庫應用里操作數據源都必須通過該對象,這是數據交換的環境。Connection對象代表了同數據源的一個會話,在客戶/服務器模型里,這個會話相當于同服務器的一次網絡連接。不同的數據提供者提供的該對象的集合、方法和屬性不同。
借助于Connection對象的集合、方法和屬性,可以使用Open和Close方法建立和釋放一個數據源連接。使用Execute方法可以執行一個數據操作命令,使用BeginTrans、CommitTrans和RollbackTrans方法可以啟動、提交和回滾一個處理事務。通過操作the Errors?集合可以獲取和處理錯誤信息,操作CommandTimeout屬性可以設置連接的溢出時間,操作ConnectionString屬性可以設置連接的字符串,操作Mode屬性可以設置連接的模式,操作Provider屬性可以指定OLE DB提供者。
2.2 Command對象
Command對象是一個對數據源執行命令的定義,使用該對象可以查詢數據庫并返回一個Recordset對象,可以執行一個批量的數據操作,可以操作數據庫的結構。不同的數據提供者提供的該對象的集合、方法和屬性不同。
借助于Command對象的集合、方法和屬性,可以使用Parameters集合制定命令的參數,可以使用Execute方法執行一個查詢并將查詢結果返回到一個Recordset對象里,操作CommandText屬性可以為該對象指定一個命令的文本,操作CommandType屬性可以指定命令的類型,操作Prepared可以得知數據提供者是否準備好命令的執行,操作CommandTimeout屬性可以設置命令執行的溢出時間。
2.3?Parameter對象
Parameter對象在Command對象中用于指定參數化查詢或者存儲過程的參數。大多數數據提供者支持參數化命令,這些命令往往是已經定義好了的,只是在執行過程中調整參數的內容。
借助于Parameter對象的集合、方法和屬性,可以通過設置Name屬性指定參數的名稱,通過設置Value屬性可以指定參數的值,通過設置Attributes和Direction、Precision、NumericScale、Size與Type?屬性可以指定參數的信息,通過執行AppendChunk方法可以將數據傳遞到參數里。
2.4 Recordset對象
如果執行的命令是一個查詢并返回存放在表中的結果集,這些結果集將被保存在本地的存儲區里,Recordset對象是執行這種存儲的ADO對象。通過Recordset對象可以操縱來自數據提供者的數據,包括修改和更新行、插入和刪除行。
2.5???Field對象
Recordset對象的一個行由一個或者多個Fields對象組成,如果把一個Recordset對象看成一個二維網格表,那么Fields對象就是這些列。這些列里保存了列的名稱、數據類型和值,這些值是來自數據源的真正數據。為了修改數據源里的數據,必須首先修改Recordset對象各個行里Field對象里的值,最后Recordset對象將這些修改提交到數據源。
借助于Field對象的集合、方法和屬性,可以通過讀取Name屬性,獲知列的名稱。通過操作Value屬性可以改變列的值,通過讀取Type、Precision和NumericScale?屬性,可獲知列的數據類型、精度和小數位的個數,通過執行AppendChunk?和GetChunk?方法可以操作列的值。
2.6?Error對象
Error對象包含了ADO數據操作時發生錯誤的詳細描述,ADO的任何對象都可以產生一個或者多個數據提供者錯誤,當錯誤發生時,這些錯誤對象被添加到Connection?對象的Errors集合里。當另外一個ADO對象產生一個錯誤時,Errors集合里的Error對象被清除,新的Error對象將被添加到Errors集合里。
借助于Errosr對象的集合、方法和屬性,可以通過讀取Number和Description屬性,獲得ADO錯誤號碼和對錯誤的描述,通過讀取Source屬性得知錯誤發生的源。
2.7??Property對象
Property對象代表了一個由提供者定義的ADO對象的動態特征。ADO對象有兩種類型的Property對象:內置的和動態的。內置的Property對象是指那些在ADO里實現的在對象創建時立即可見的屬性,可以通過域作用符直接操作這些屬性。動態的Property對象是指由數據提供者定義的底層的屬性,這些屬性出現在ADO對象的Properties集合里,例如,如果一個Recordset?對象支持事務和更新,這些屬性將作為Property對象出現在Recordset對象的Properties集合里。動態屬性必須通過集合進行引用,比如使用下面的語法:
???MyObject.Properties(0)???
或者
????????MyObject.Properties("Name")
不能刪除任何類型的屬性對象。借助于Property對象的集合、方法和屬性,可以通過讀取Name屬性獲得屬性的名稱,通過讀取Type屬性獲取屬性的數據類型,通過讀取Value屬性獲取屬性的值。
三、ADO編程
通常情況下,一個基于ADO的數據庫應用使用如下過程操作數據源里的數據:
(1)?創建一個Connection對象。定義用于連接的字符串信息,包括數據源名稱、用戶ID、口令、連接超時、缺省數據庫以及光標的位置。一個Connection?對象代表了同數據源的一次會話。可以通過Connection?對象控制事務,即執行BeginTrans、CommitTrans和RollbackTrans方法。
(2)?打開數據源,建立同數據源的連接。
(3)?執行一個SQL命令。一旦連接成功,就可以運行查詢了。可以以異步方式運行查詢,也可以異步地處理查詢結果,ADO會通知提供者后臺提供數據。這樣可以讓應用程序繼續處理其它事情而不必等待。
(4)?使用結果集。完成了查詢以后,結果集就可以被應用程序使用了。在不同的光標類型下,可以在客戶端或者服務器端瀏覽和修改行數據。
(5)?終止連接。當完成了所有數據操作后,可以銷毀這個同數據源的連接。
3.1準備工作
引入ADO庫
???ADO是以DLL封裝的,要使用ADO,首先得引入其DLL庫,引入ADO類型庫的方法有多種,在此我們就介紹一種----通過預處理指令#import引入。一般情況下,在windows操作系統的Program Files\Common Files\System\ado目錄下都有一個msado*.dll文件,根據windows版本不同,該文件可以是msado1.dll、msado15.dll、msado2.dll,對于此文件,版本不一樣,可能導致一些沖突,如:系統自帶的msado*.dll可能與程序編譯所用的版本不一樣,可能會導致一些異常,那么對于這種情況,我個人一般的做法是,在軟件目錄下面帶上msado*.dll文件,這樣就排除了對軟件運行環境的依賴。
?Ado類型庫引入后,程序在編譯過程中,VC++會讀出msado*.dll中的類型庫信息,自動產生兩個該類型庫的頭文件和實現文件msado15.tlh和msado15.tli(在您的Debug或Release目錄下)。在這兩個文件里定義了ADO的所有對象和方法,以及一些枚舉型的常量等。以下是引入方法:
//收下引入命令會導致4146警告,通過些命令去除#pragma warning(disable:4146)//引號里面的路徑,可絕對的,可相對的 #import"..\CommFile\Lib\msado15.dll" named_guids \ //重命名EOF與BOF以免與其他命名空間沖突rename("EOF","adoEOF"),rename("BOF","adoBOF")#pragma warning(default:4146)using namespace ADODB;初始化COM
ADO是COM組件,使用任何COM組件的時候,都要先初始化COM,其實就是在使用COM組件前調用一個API----CoInitialize(),在使用ADO對象之前調用即可,以下為代碼:
HRESULT hr =CoInitialize(NULL); ASSERT(SUCCEEDED(hr));//返回值可判斷初始化COM是否成功,請用SUCCEEDED來判斷一般情況下,使用完COM之后,調用反初始化COM函數----CoUninitialize()。一般會在數據庫訪問封裝類的析構函數中調用。
3.2連接數據庫
通過創建連接對象連接數據庫,首先創建一個指向Connection的指針_ConnectionPtr,以下是創建連接的源碼:
ConnectionPtr m_pConn;HRESULT hr =CoInitialize(NULL);ASSERT(SUCCEEDED(hr));if (NULL ==m_pConn) {try{ //Connectingif ( !FAILED(m_pConn.CreateInstance(_uuidof(Connection)))){ //設置連接超時時間m_pConn->CommandTimeout= 30; //設置連接超時值,單位為秒if (!FAILED(m_pConn->Open((_bstr_t)(m_szConnStr), "", "",adModeUnknown)))returntrue;}}catch(_com_error e){char szLog[MAX_BUFF];memset(szLog, 0, MAX_BUFF);sprintf(szLog, "連接數據庫錯誤:%s\n",(char *)(e.Description()));}return false;}Open方法中,?第一個參數就是連接串,這個連接串如何獲得?VC++6.0中有工具,不過太過麻煩,而且獲得的串還得復制,不方便,下面介紹一種方便實用獲得連接串的方法。
3.3獲得記錄集
??與Connection對象一樣,首先是創建一個RecordSet對象指針,再創建對象
try{if(!FAILED(m_pRecord.CreateInstance(__uuidof(Recordset)))) {HRESULT hr = 0;//當連接斷開,或者連接對象沒有連接的情況下,通過連接串獲得記錄集if (NULL == m_pConn ||adStateClosed == m_pConn->State)hr =m_pRecord->Open((_bstr_t)szSQL, _variant_t(m_szConnStr),adOpenKeyset, adLockOptimistic,adCmdText);else//連接對象處理正常連接狀態下,直接使用hr = m_pRecord->Open((_bstr_t)szSQL,m_pConn.GetInterfacePtr(), adOpenKeyset,adLockOptimistic,adCmdText);if (SUCCEEDED(hr)) bResult = true;}}catch (_com_errore){char szLog[MAX_BUFF]; memset(szLog, 0,MAX_BUFF);sprintf(szLog, "執行SQL查詢命令錯誤:%s[%s]",(char *)(e.Description()), szSQL);}以上代碼中的szSQL是select串,就是查詢語句,if與else中m_pRecord有兩種Open方式,第一種是連接對象斷開,或者沒連接狀態下,通過連接串獲得記錄集,第二種連接正常情況下,那么無需再連接,直接通過連接對象獲得連接信息。至此,記住集已成功獲得,下面是怎么提取數據的問題了。
while(!IsRecordEOF()){//判斷是否到了記錄結尾UINT nCarID = 0;char sCarMark[MAX_BUFF];memset(sCarMark, 0, MAX_BUFF);CollectMsg("CARID" , nCarID ) ;//第一個參數,傳列名CollectMsg("Car_Mark" , sCarMark, MAX_BUFF) ;RecordMoveNext();//移動到下一個記錄}CloseRecord ();//關閉記錄集以下代碼是以上代碼的函數實現:Bool IsRecordEOF(){bool bResult = true;if (NULL != m_pRecord) {if (!m_pRecord->adoEOF)bResult = false;}return bResult;}Bool CollectMsg(const char *szColumnName, int&iTemp ){bool bResult = false;if (adStateClosed !=m_pRecord->State) {try{_variant_t Column(szColumnName);_variant_t RusultGet= m_pRecord->Fields->GetItem(Column)->Value;iTemp =RusultGet.intVal;bResult = true;}catch(_com_error e){charszLog[MAX_BUFF]; memset(szLog, 0, MAX_BUFF);sprintf(szLog,"%s", (char *)(e.Description()));m_WriteLog.WriteLog(szLog,strlen(szLog), LOG_ERR);}}return bResult;}Bool CollectMsg(const char *szColumnName, char*szBuff, int nBuffSize){bool bResult = false;if (adStateClosed !=m_pRecord->State) {try{_variant_t Column(szColumnName);_variant_t RusultGet= m_pRecord->Fields->GetItem(Column)->Value;WideCharToMultiByte(CP_ACP,0, RusultGet.bstrVal, -1, szBuff, nBuffSize,NULL, NULL);bResult = true;}catch(_com_error e){charszLog[MAX_BUFF]; memset(szLog, 0, MAX_BUFF);sprintf(szLog,"%s", (char *)(e.Description()));m_WriteLog.WriteLog(szLog,strlen(szLog), LOG_ERR);}}return bResult;}Bool RecordMoveNext(){bool bResult = false;if (NULL != m_pRecord) {if (!m_pRecord->adoEOF) {try{m_pRecord->MoveNext();bResult =true;}catch(_com_error e){charszLog[MAX_BUFF]; memset(szLog, 0, MAX_BUFF);sprintf(szLog,"RecordMoveNext錯誤:%s\n", (char *)(e.Description()));m_WriteLog.WriteLog(szLog,strlen(szLog), LOG_ERR);}}}return bResult;}Void CloseRecord (void){try{if (NULL != m_pRecord){m_pRecord->Close();m_pRecord = NULL;}}catch(_com_error e){char szLog[MAX_BUFF];memset(szLog, 0, MAX_BUFF);sprintf(szLog, "關閉數據記錄集錯誤:%s\n",(char *)(e.Description()));m_WriteLog.WriteLog(szLog,strlen(szLog), LOG_ERR);}}3.4執行SQL命令
可通過Command對象來執行命令,也可以直接通過Connection對象來執行,以下介紹通過Connection對象來執行命令,命令可以是Updata命令,Insert命令等,以下是代碼:
//第一個參數是要執行的命令,第二個參數用來返回影響的行數Bool ExecuteSQL(const char *szSQLStr, long&nRefreshNum){bool bResult = false;if (strlen(szSQLStr) > 0) {if (NULL == m_pConn ||adStateClosed == m_pConn->State)ConnDB();try{_variant_tRefreshNum;m_pConn->Execute(_bstr_t(szSQLStr),&RefreshNum, adCmdText);bResult = true;nRefreshNum =RefreshNum.lVal;}catch (_com_error e){nRefreshNum = 0;charszLog[MAX_BUFF]; memset(szLog, 0, MAX_BUFF);sprintf(szLog,"執行SQL命令錯誤:%s[%s]", (char *)(e.Description()), szSQLStr);m_WriteLog.WriteLog(szLog,strlen(szLog), LOG_ERR);}}return bResult;}3.5關閉連接、記錄集
連接對象與記錄集使用完之后,要關閉:????????
if (NULL !=m_pConn)m_pConn->Close();if (NULL !=m_pRecord){m_pRecord->Close();參考:ADO編程詳解(C++)_LearnLHC的博客-CSDN博客_ado c++
總結
以上是生活随笔為你收集整理的ADO编程详解(C++)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ado全称_JDBC、ODBC、OLE
- 下一篇: python代码加密解密_Python实