馮曉星 馬曉靜
(電子工程學院 安徽 合肥 230037)
在開發數據庫應用軟件中,Visual C++提供了多種訪問接口,相比較早期基于ODBC的DAO、RDO等技術,建立在OLE/DB之上的ADO(ActiveX DataObjects)技術無疑更加高效快捷。ADO能夠處理任何類型的數據,而不考慮它們的格式和存儲方法。這些數據源不僅包括關系型數據庫,也包含非關系型數據庫。由于它具有強大的數據處理功能和極其簡單、易用的特點,因而已成為當前數據庫開發的主流[1,2]。
ADO數據庫接口繼承了DAO和RDO所使用的對象模型,并加以改進,包含了較少的對象、更多的屬性方法(和參數)和事件。ADO有7個對象:Command對象、Connection對象、Recordset對象、Parameter對象、Field 對象、Error對象和Property對象,其中前3個對象是主體對象也是基本對象,它們可以被獨立創建和釋放。
在訪問數據庫之前需建立與數據源的連接并保持,這一過程用Connection對象實現,通過和SQL語句結合創建一個連接。利用Command對象和Recordset對象都可在執行數據庫操作后返回一個記錄集。和Connection對象一樣,Command對象通過與SQL語句相結合的方法可以完成對數據庫的簡單快捷操作,而Recordset對象可以提供更多的數據庫操作控制功能,如記錄鎖定,游標控制等[3]。
使用ADO訪問數據庫之前有2個準備步驟。
⑴導入ADO類型庫
ADO DLL(msado15.dll)中定義了ADO類,在其內部稱為類型庫。一般在stdafx.h頭文件中,使用#import指令導入ADO類型庫,以此創建一組C++頭文件,程序語句如下:

根據Windows操作系統版本的不同,動態鏈接庫文件可能是msado10.dll、msado15.dll或msado20.dll,需根據實際情況進行修改。no_namespace的意思是該應用程序中,ADO對象的命名不存在和其他對象沖突的情況,不使用命名空間,重命名EOF和BOF是為了避免與其他庫中的已定義的EOF和BOF沖突。
⑵初始化COM庫
因為ADO庫是一個COM動態鏈接庫,所以使用ADO對象之前必須初始化COM庫環境,調用結束后再釋放資源。初始化的代碼為函數::Co Initialize(NULL),釋放程序占用資源的代碼為:CoUninitialize(),分別在VC工程應用類的InitInstance()成員函數和ExitInstance()成員函數中添加。
對于ADO的3個主體對象,動態鏈接庫分別定義了3個智能指針,_ConnectionPtr指針對應 Connection對象、_CommandPtr指針對應Command對象,_RecordsetPtr指針對應Recordset對象。操作數據庫之前需建立一個數據庫連接,其操作步驟是:首先聲明一個_ConnectionPtr指針并調用CreateInstance()函數創建一個Connection對象實例,然后調用open()函數建立到數據源的連接。
連接Access數據庫的示例程序代碼如下:

上面代碼用try、catch語句進行錯誤捕捉,因為連接數據庫時經常會發生意想不到的錯誤。“Microsoft.Jet.OLEDB.4.0”代表通過JET數據庫引擎連接數據庫,“DataBase.mdb”是登錄的數據庫名,可根據具體情況進行修改,數據庫的用戶ID和密碼為缺省,當前的許可權未設置。
在應用程序中,一般在使用完成數據庫后,應該關閉與數據源的連接。ADO在關閉連接的同時,也將關閉所有使用這個連接的ADO對象。關閉連接的代碼如下:

要操作訪問數據庫,就必須先打開記錄集。利用Command對象和Recordset對象結合SQL語句均可得到記錄集。
3.2.1 利用Command對象來執行SQL命令
聲明一個_CommandPtr指針并調用CreateInstance()函數創建一個Command對象實例,利用Execute方法得到記錄集。代碼如下:

利用Select查詢語句,返回一個記錄集,可先定義一個記錄集指針,然后指向返回的記錄集。
3.2.2 直接利用Recordset對象進行查詢
在ADO數據庫編程中,Recordset對象代表一個表的記錄集或者是一個SQL語句或存儲過程的執行結果。通過Recordset對象就可以更方便地進行查詢、添加記錄、修改記錄和刪除記錄等的操作。其操作步驟是:首先聲明一個_RecordsetPtr指針并調用CreateInstance()函數創建一個Recordset對象實例,然后調用Open()函數打開記錄集。Open()函數原型如下:

其中,參數Source用于指定打開記錄集的數據源,它可以是Command對象變量、SQL語句、表名或存儲過程;ActiveConnection是一個連接對象的變量名或者是一個包含連接信息的字符串,用于指定是在哪一個連接中打開記錄集;CursorType是一個CursorTypeEnum枚舉類型常量,用于指定打開記錄集時使用的游標,取值可以是adOpenStatic(靜態游標)、adOpenDynam ic(動態游標)、adOpenForwardOnly(前向游標)和adOpenKeyset(鍵集游標)之一;LockType是一個LockTypeEnum枚舉類型常量,用于指定打開記錄集時使用的鎖定類型,取值可以是adLockReadOnly(只讀)、adLockPessim istic(悲觀鎖定)、adLockOptim istic(樂觀鎖定)和adLockBatchOptim istic(樂觀批量更新)之一。Options是一個選項,表示ADO如何解釋源數據,取值可以是adCmdText(Source是文本)、adCmdTable(表名)、adCmdStoreProc(存儲過程)、adCmdUnknow n(未知)[4]。
示例程序代碼如下:

對記錄集的操作完成后,應關閉記錄,釋放占用的系統資源。調用Recordset對象的Close()函數可以關閉記錄集,示例代碼如下:

3.2.3 在記錄集中定位
一個數據庫由若干個表組成,表的行稱為記錄。ADO對象若要訪問記錄,需要先將游標停在記錄集的該行前,即定位。Recordset對象提供了 4個成員函數:MovePrevious()、M oveNext()、M oveFirst()和 M oveLast(),控制游標移動,以進行定位。MoveFirst()是將游標移至表中的第一條記錄,MoveLast()是將游標移至表中最后一條記錄,M ovePrevious()是將游標移至當前記錄的前一條記錄,M oveNext()是將是將游標移至當前記錄的后一條記錄。代碼如下:

這里通過if語句判斷游標是否已移到了第一條記錄的前面(Before of File),返回一個布爾值。同理,通過判斷Recordset對象屬性adoEOF的值,就可以知道游標是否移到了最后一條記錄的后面(End of File)。
3.2.4 獲取或修改字段的值
一行記錄里可能有很多屬性,即字段。游標定位好之后,通過調用GetCollect()函數,就可以獲取當前記錄中各個字段的值。該函數的原型如下:

其中,參數Index可以是要獲取值的字段的索引號,也可以是要獲取值的字段的名稱[5,6]。
例如,現要獲取當前記錄的時間“Time”字段的值,代碼如下:

通過調用PutCollect()函數,可以修改當前記錄各字段的值。該函數的原型如下:

其中,參數Index的含義與GetCollect()函數中相同;參數pvar用于給出修改值,它可以是一個具體值,也可以是一個變量。
例如,將當前記錄的“Time”字段的值改為“2012/12/7”,示例代碼如下:

如果第2個參數給出的是CString型變量,則需要進行類型轉換。示例代碼如下:

綜上所述,建立在OLE/DB基礎之上的ADO封裝了具體訪問數據庫的細節,使程序員從具體的數據庫管理軟件中解放出來,即使對OLE/DB,COM不了解也能輕松應用。通過利用ADO對象可方便快捷地連接數據庫并操作,使得軟件開發的周期大大縮短,并具有維護方便可靠的優點。
[1]劉天印.基于VC++的數據庫訪問技術的比較與選擇[J].黃石:黃石理工學院學報,2005(4):15-18.
[2]史嘉權.數據庫系統概論[M].北京:高等教育出版社,2006:10-15.
[3]王聰華.ADO訪問數據庫實例剖析[J].計算機應用研究,2002(5):159-160.
[4][美]DavisChapman著,駱長樂譯.常用VisualC++6.0[M].北京:清華大學出版社,1999.
[5]鄭阿奇.VisualC++教程[M].北京:機械工業出版社,2004.
[6]魏 朗,陳 濤.VisualC++程序設計攻略教程[M].西安:西安電子科技出版社,2004.