馮曉星 馬曉靜
(電子工程學(xué)院 安徽 合肥 230037)
在開(kāi)發(fā)數(shù)據(jù)庫(kù)應(yīng)用軟件中,Visual C++提供了多種訪問(wèn)接口,相比較早期基于ODBC的DAO、RDO等技術(shù),建立在OLE/DB之上的ADO(ActiveX DataObjects)技術(shù)無(wú)疑更加高效快捷。ADO能夠處理任何類型的數(shù)據(jù),而不考慮它們的格式和存儲(chǔ)方法。這些數(shù)據(jù)源不僅包括關(guān)系型數(shù)據(jù)庫(kù),也包含非關(guān)系型數(shù)據(jù)庫(kù)。由于它具有強(qiáng)大的數(shù)據(jù)處理功能和極其簡(jiǎn)單、易用的特點(diǎn),因而已成為當(dāng)前數(shù)據(jù)庫(kù)開(kāi)發(fā)的主流[1,2]。
ADO數(shù)據(jù)庫(kù)接口繼承了DAO和RDO所使用的對(duì)象模型,并加以改進(jìn),包含了較少的對(duì)象、更多的屬性方法(和參數(shù))和事件。ADO有7個(gè)對(duì)象:Command對(duì)象、Connection對(duì)象、Recordset對(duì)象、Parameter對(duì)象、Field 對(duì)象、Error對(duì)象和Property對(duì)象,其中前3個(gè)對(duì)象是主體對(duì)象也是基本對(duì)象,它們可以被獨(dú)立創(chuàng)建和釋放。
在訪問(wèn)數(shù)據(jù)庫(kù)之前需建立與數(shù)據(jù)源的連接并保持,這一過(guò)程用Connection對(duì)象實(shí)現(xiàn),通過(guò)和SQL語(yǔ)句結(jié)合創(chuàng)建一個(gè)連接。利用Command對(duì)象和Recordset對(duì)象都可在執(zhí)行數(shù)據(jù)庫(kù)操作后返回一個(gè)記錄集。和Connection對(duì)象一樣,Command對(duì)象通過(guò)與SQL語(yǔ)句相結(jié)合的方法可以完成對(duì)數(shù)據(jù)庫(kù)的簡(jiǎn)單快捷操作,而Recordset對(duì)象可以提供更多的數(shù)據(jù)庫(kù)操作控制功能,如記錄鎖定,游標(biāo)控制等[3]。
使用ADO訪問(wèn)數(shù)據(jù)庫(kù)之前有2個(gè)準(zhǔn)備步驟。
⑴導(dǎo)入ADO類型庫(kù)
ADO DLL(msado15.dll)中定義了ADO類,在其內(nèi)部稱為類型庫(kù)。一般在stdafx.h頭文件中,使用#import指令導(dǎo)入ADO類型庫(kù),以此創(chuàng)建一組C++頭文件,程序語(yǔ)句如下:
根據(jù)Windows操作系統(tǒng)版本的不同,動(dòng)態(tài)鏈接庫(kù)文件可能是msado10.dll、msado15.dll或msado20.dll,需根據(jù)實(shí)際情況進(jìn)行修改。no_namespace的意思是該應(yīng)用程序中,ADO對(duì)象的命名不存在和其他對(duì)象沖突的情況,不使用命名空間,重命名EOF和BOF是為了避免與其他庫(kù)中的已定義的EOF和BOF沖突。
⑵初始化COM庫(kù)
因?yàn)锳DO庫(kù)是一個(gè)COM動(dòng)態(tài)鏈接庫(kù),所以使用ADO對(duì)象之前必須初始化COM庫(kù)環(huán)境,調(diào)用結(jié)束后再釋放資源。初始化的代碼為函數(shù)::Co Initialize(NULL),釋放程序占用資源的代碼為:CoUninitialize(),分別在VC工程應(yīng)用類的InitInstance()成員函數(shù)和ExitInstance()成員函數(shù)中添加。
對(duì)于ADO的3個(gè)主體對(duì)象,動(dòng)態(tài)鏈接庫(kù)分別定義了3個(gè)智能指針,_ConnectionPtr指針對(duì)應(yīng) Connection對(duì)象、_CommandPtr指針對(duì)應(yīng)Command對(duì)象,_RecordsetPtr指針對(duì)應(yīng)Recordset對(duì)象。操作數(shù)據(jù)庫(kù)之前需建立一個(gè)數(shù)據(jù)庫(kù)連接,其操作步驟是:首先聲明一個(gè)_ConnectionPtr指針并調(diào)用CreateInstance()函數(shù)創(chuàng)建一個(gè)Connection對(duì)象實(shí)例,然后調(diào)用open()函數(shù)建立到數(shù)據(jù)源的連接。
連接Access數(shù)據(jù)庫(kù)的示例程序代碼如下:
上面代碼用try、catch語(yǔ)句進(jìn)行錯(cuò)誤捕捉,因?yàn)檫B接數(shù)據(jù)庫(kù)時(shí)經(jīng)常會(huì)發(fā)生意想不到的錯(cuò)誤?!癕icrosoft.Jet.OLEDB.4.0”代表通過(guò)JET數(shù)據(jù)庫(kù)引擎連接數(shù)據(jù)庫(kù),“DataBase.mdb”是登錄的數(shù)據(jù)庫(kù)名,可根據(jù)具體情況進(jìn)行修改,數(shù)據(jù)庫(kù)的用戶ID和密碼為缺省,當(dāng)前的許可權(quán)未設(shè)置。
在應(yīng)用程序中,一般在使用完成數(shù)據(jù)庫(kù)后,應(yīng)該關(guān)閉與數(shù)據(jù)源的連接。ADO在關(guān)閉連接的同時(shí),也將關(guān)閉所有使用這個(gè)連接的ADO對(duì)象。關(guān)閉連接的代碼如下:
要操作訪問(wèn)數(shù)據(jù)庫(kù),就必須先打開(kāi)記錄集。利用Command對(duì)象和Recordset對(duì)象結(jié)合SQL語(yǔ)句均可得到記錄集。
3.2.1 利用Command對(duì)象來(lái)執(zhí)行SQL命令
聲明一個(gè)_CommandPtr指針并調(diào)用CreateInstance()函數(shù)創(chuàng)建一個(gè)Command對(duì)象實(shí)例,利用Execute方法得到記錄集。代碼如下:
利用Select查詢語(yǔ)句,返回一個(gè)記錄集,可先定義一個(gè)記錄集指針,然后指向返回的記錄集。
3.2.2 直接利用Recordset對(duì)象進(jìn)行查詢
在ADO數(shù)據(jù)庫(kù)編程中,Recordset對(duì)象代表一個(gè)表的記錄集或者是一個(gè)SQL語(yǔ)句或存儲(chǔ)過(guò)程的執(zhí)行結(jié)果。通過(guò)Recordset對(duì)象就可以更方便地進(jìn)行查詢、添加記錄、修改記錄和刪除記錄等的操作。其操作步驟是:首先聲明一個(gè)_RecordsetPtr指針并調(diào)用CreateInstance()函數(shù)創(chuàng)建一個(gè)Recordset對(duì)象實(shí)例,然后調(diào)用Open()函數(shù)打開(kāi)記錄集。Open()函數(shù)原型如下:
其中,參數(shù)Source用于指定打開(kāi)記錄集的數(shù)據(jù)源,它可以是Command對(duì)象變量、SQL語(yǔ)句、表名或存儲(chǔ)過(guò)程;ActiveConnection是一個(gè)連接對(duì)象的變量名或者是一個(gè)包含連接信息的字符串,用于指定是在哪一個(gè)連接中打開(kāi)記錄集;CursorType是一個(gè)CursorTypeEnum枚舉類型常量,用于指定打開(kāi)記錄集時(shí)使用的游標(biāo),取值可以是adOpenStatic(靜態(tài)游標(biāo))、adOpenDynam ic(動(dòng)態(tài)游標(biāo))、adOpenForwardOnly(前向游標(biāo))和adOpenKeyset(鍵集游標(biāo))之一;LockType是一個(gè)LockTypeEnum枚舉類型常量,用于指定打開(kāi)記錄集時(shí)使用的鎖定類型,取值可以是adLockReadOnly(只讀)、adLockPessim istic(悲觀鎖定)、adLockOptim istic(樂(lè)觀鎖定)和adLockBatchOptim istic(樂(lè)觀批量更新)之一。Options是一個(gè)選項(xiàng),表示ADO如何解釋源數(shù)據(jù),取值可以是adCmdText(Source是文本)、adCmdTable(表名)、adCmdStoreProc(存儲(chǔ)過(guò)程)、adCmdUnknow n(未知)[4]。
示例程序代碼如下:
對(duì)記錄集的操作完成后,應(yīng)關(guān)閉記錄,釋放占用的系統(tǒng)資源。調(diào)用Recordset對(duì)象的Close()函數(shù)可以關(guān)閉記錄集,示例代碼如下:
3.2.3 在記錄集中定位
一個(gè)數(shù)據(jù)庫(kù)由若干個(gè)表組成,表的行稱為記錄。ADO對(duì)象若要訪問(wèn)記錄,需要先將游標(biāo)停在記錄集的該行前,即定位。Recordset對(duì)象提供了 4個(gè)成員函數(shù):MovePrevious()、M oveNext()、M oveFirst()和 M oveLast(),控制游標(biāo)移動(dòng),以進(jìn)行定位。MoveFirst()是將游標(biāo)移至表中的第一條記錄,MoveLast()是將游標(biāo)移至表中最后一條記錄,M ovePrevious()是將游標(biāo)移至當(dāng)前記錄的前一條記錄,M oveNext()是將是將游標(biāo)移至當(dāng)前記錄的后一條記錄。代碼如下:
這里通過(guò)if語(yǔ)句判斷游標(biāo)是否已移到了第一條記錄的前面(Before of File),返回一個(gè)布爾值。同理,通過(guò)判斷Recordset對(duì)象屬性adoEOF的值,就可以知道游標(biāo)是否移到了最后一條記錄的后面(End of File)。
3.2.4 獲取或修改字段的值
一行記錄里可能有很多屬性,即字段。游標(biāo)定位好之后,通過(guò)調(diào)用GetCollect()函數(shù),就可以獲取當(dāng)前記錄中各個(gè)字段的值。該函數(shù)的原型如下:
其中,參數(shù)Index可以是要獲取值的字段的索引號(hào),也可以是要獲取值的字段的名稱[5,6]。
例如,現(xiàn)要獲取當(dāng)前記錄的時(shí)間“Time”字段的值,代碼如下:
通過(guò)調(diào)用PutCollect()函數(shù),可以修改當(dāng)前記錄各字段的值。該函數(shù)的原型如下:
其中,參數(shù)Index的含義與GetCollect()函數(shù)中相同;參數(shù)pvar用于給出修改值,它可以是一個(gè)具體值,也可以是一個(gè)變量。
例如,將當(dāng)前記錄的“Time”字段的值改為“2012/12/7”,示例代碼如下:
如果第2個(gè)參數(shù)給出的是CString型變量,則需要進(jìn)行類型轉(zhuǎn)換。示例代碼如下:
綜上所述,建立在OLE/DB基礎(chǔ)之上的ADO封裝了具體訪問(wèn)數(shù)據(jù)庫(kù)的細(xì)節(jié),使程序員從具體的數(shù)據(jù)庫(kù)管理軟件中解放出來(lái),即使對(duì)OLE/DB,COM不了解也能輕松應(yīng)用。通過(guò)利用ADO對(duì)象可方便快捷地連接數(shù)據(jù)庫(kù)并操作,使得軟件開(kāi)發(fā)的周期大大縮短,并具有維護(hù)方便可靠的優(yōu)點(diǎn)。
[1]劉天印.基于VC++的數(shù)據(jù)庫(kù)訪問(wèn)技術(shù)的比較與選擇[J].黃石:黃石理工學(xué)院學(xué)報(bào),2005(4):15-18.
[2]史嘉權(quán).數(shù)據(jù)庫(kù)系統(tǒng)概論[M].北京:高等教育出版社,2006:10-15.
[3]王聰華.ADO訪問(wèn)數(shù)據(jù)庫(kù)實(shí)例剖析[J].計(jì)算機(jī)應(yīng)用研究,2002(5):159-160.
[4][美]DavisChapman著,駱長(zhǎng)樂(lè)譯.常用VisualC++6.0[M].北京:清華大學(xué)出版社,1999.
[5]鄭阿奇.VisualC++教程[M].北京:機(jī)械工業(yè)出版社,2004.
[6]魏 朗,陳 濤.VisualC++程序設(shè)計(jì)攻略教程[M].西安:西安電子科技出版社,2004.
計(jì)算機(jī)與網(wǎng)絡(luò)2013年8期