ADO (ActiveX Data Objects,ActiveX數據對象)是Microsoft提出的套用程式接口(API)用以實現訪問關係或非關係資料庫中的數據。例如,如果您希望編寫應用程式從DB2或Oracle資料庫中向網頁提供數據,可以將ADO程式包括在作為活動伺服器頁(ASP)的HTML檔案中。當用戶從網站請求網頁時,返回的網頁也包括了數據中的相應數據,這些是由於使用了ADO代碼的結果。
象Microsoft的其它系統接口一樣,ADO是面向對象的。它是Microsoft全局數據訪問(UDA)的一部分,Microsoft認為與其自己創建一個數據,不如利用UDA訪問已有的資料庫。為達到這一目的,Microsoft和其它資料庫公司在它們的資料庫和Microsoft的OLE資料庫之間提供了一個“橋”程式,OLE資料庫已經在使用ADO技術。ADO的一個特徵(稱為遠程數據服務)支持網頁中的數據相關的ActiveX控制項和有效的客戶端緩衝。作為ActiveX的一部分,ADO也是Microsoft的組件對象模式(COM)的一部分,它的面向組件的框架用以將程式組裝在一起。
ADO從原來的Microsoft數據接口遠程數據對象(RDO)而來。RDO與ODBC一起工作訪問關係資料庫,但不能訪問如ISAM和VSAM的非關係資料庫。
ADO 是對當前微軟所支持的資料庫進行操作的最有效和最簡單直接的方法,它是一種功能強大的數據訪問編程模式,從而使得大部分數據源可程式的屬性得以直接擴展到你的Active Server 頁面上。可以使用ADO 去編寫緊湊簡明的腳本以便連線到 Open Database Connectivity (ODBC) 兼容的資料庫和 OLE DB 兼容的數據源,這樣 ASP 程式設計師就可以訪問任何與 ODBC 兼容的資料庫,包括 MS SQL SERVER、Access、 Oracle 等等。
比如,如果網站開發人員需要讓用戶通過訪問網頁來獲得存在於IBM DB2或者Oracle資料庫中的數據,那么就可以在ASP頁面中包含ADO程式,用來連線資料庫。於是,當用戶在網站上瀏覽網頁時,返回的網頁將會包含從資料庫中獲取的數據。而這些數據都是由ADO代碼做到的。
ADO是一種面向對象的編程接口,微軟介紹說,與其同IBM和Oracle提倡的那樣,創建一個統一資料庫,不如提供一個能夠訪問不同資料庫的統一接口,這樣會更加實用一些。為實現這一目標,微軟在資料庫和微軟的OLE DB中提供了一種“橋”程式,這種程式能夠提供對資料庫的連線。開發人員在使用ADO時,其實就是在使用OLE DB,不過OLE DB更加接近底層。ADO的一項屬性??遠程數據服務,支持“數據倉庫”ActiveX 組件以及高效的客戶端快取。作為ActiveX的一部分,ADO也是COM組件的一部分。ADO是由早期的微軟數據接口??遠程數據對象RDO演化而來的。RDO同微軟的ODBC一同連線關係資料庫,不過不能連線非關係資料庫。
ADO向我們提供了一個熟悉的,高層的對OLE DB的Automation封裝接口。對那些熟悉RDO的程式設計師來說,你可以把OLE DB比作是ODBC驅動程式。如同RDO對象是ODBC驅動程式接口一樣,ADO對象是OLE DB的接口;如同不同的資料庫系統需要它們自己的ODBC驅動程式一樣,不同的數據源要求它們自己的OLE DB提供者(OLE DB provider)。目前,雖然OLE DB提供者比較少,但微軟正積極推廣該技術,並打算用OLE DB取代ODBC。
ADO向VB程式設計師提供了很多好處。包括易於使用,熟悉的界面,高速度以及較低的記憶體占用(已實現ADO2.0的Msado15.dll需要占用342K記憶體,比RDO的msrdo20.dll的368K略小,大約是DAO3.5的Dao350.dll所占記憶體的60%)。同傳統的數據對象層次(DAO和RDO)不同,ADO可以獨立創建。因此你可以只創建一個"Connection"對象,但是可以有多個,獨立的"Recordset"對象來使用它。ADO針對客戶/伺服器以及WEB應用程式作了最佳化。
一、ADO 對象總結
對象 | 說明 |
Command | Command 對象定義了將對數據源執行的指定命令。 |
Connection | 代表打開的、與數據源的連線。 |
DataControl ( RDS) | 將數據查詢 Recordset 綁定到一個或多個控制項上(例如,文本框、格線控制項或組合框),以便在 Web 頁上顯示 ADOR.Recordset 數據。 |
datafactory (RDS Server) | 實現對客戶端應用程式的指定數據源進行讀/寫數據訪問的方法。 |
DataSpace (RDS) | 創建客戶端代理以便自定義位於 中間層的 業務對象。 |
Error | 包含與單個操作(涉及提供者)有關的數據訪問錯誤的詳細信息。 |
Field | 代表使用普通數據 類型的數據的列。 |
Parameter | 代表與基於 參數化查詢或存儲過程的 Command 對象相關聯的參數或自變數。 |
Property | 代表由提供者定義的 ADO 對象的動態特性。 |
RecordSet | 代表來自基本表或命令執行結果的記錄的全集。任何時候, Recordset 對象所指的當前記錄均為集合內的單個記錄。 |
二、ADO 事件
ActiveX 數據對象 (ADO) 是添加到 Microsoft Active Server Pages (ASP) 的一套高級別接口,有利於伺服器端與資料庫的連線。ADO 與低級別接口 (OLE DB) 一起使用則有利於 Microsoft Universal Data Access 策略。ADO 2.0 版可生成 Visual Studio Analyzer 事件。可使用這些事件跟蹤分散式應用程式中的 ADO 互動。
ADO 生成的 Visual Studio Analyzer 事件
事件 | 事件描述 | 事件數據 |
ConnectionClose | 指示 ADO 要與 OLE DB 數據源下線。 | 無。 |
ConnectionOpen | 指示 ADO 正在連線到 OLE DB 數據源。 | 如果客戶端提供,則為連線到數據源所用的連線字元串。 |
Find | 指示 ADO 客戶端已調用 ADO Recordset.Find 函式。 | “查找”操作的判據;根據該判據匹配記錄。 |
GetRows | 指示 ADO 客戶端已調用 ADO Recordset.GetRows 函式。 | 提取的行數。 |
QueryResult | 指示資料庫已返迴響應查詢的結果集。 | 無。 |
QuerySend | 指示 ADO 正在執行命令。該事件可由下列函式觸發: Connection.Execute Command.Execute Connection.<存儲過程名> Recordset.Open | 構成查詢的 SQL 語句。 |
RecordsetOpen | 指示 ADO 正在打開遠程伺服器上的記錄集。僅適用於三層方案。 | 打開記錄集的源(通常為行返回的命令文本)。 |
Sort | 指示 ADO 準備篩選或對數據排序。 | 排序或篩選套用於記錄集數據的判據。 |
Transaction Rollback | 指示 ADO 要中止當前本地事務。 | 返回真或假。如果為真,則保持中止,即該事務中止後緊跟著開始另一事務。如果為假,則不保持中止。 |
TransactionCommit | 指示 ADO 正在提交 OLE DB 提供程式上的本地事務。 | 返回真或假。如果為真,則保留提交,即該事務提交後緊跟著開始另一事務。如果為假,則不保留提交。 |
TransactionStart | 指示 ADO 正在開始 OLE DB 提供程式上的本地事務。 | ADO 開始事務所基於的隔離級別。隔離級別指示可看到其他事務所做更改的哪一級別。 |
UpdateBatch | 指示 ADO 正在向提供程式傳送更新批處理。僅適用於三層方案。 | 如果有,為 ADO 將更新傳送到的遠程伺服器名。 |
三、在哪裡能得到ADO?
目前ADO1.5版已經可以從微軟網站免費下載。到目前為止,微軟網站仍是你獲取有關ADO最新信息的最佳場所。ADO1.5是作為OLE DB SDK的一部分提供的。你可以從下面這個網址下載:
http://www.microsoft.com/data/oledb/download.htm
在下載之前請先確認OLE DB SDK提供的各項特性。下載檔案大約有15M,如果完全安裝的話要占用80M的硬碟空間。如果你只對ADO感舉趣,就選擇最小安裝,這樣只會占用你15M的硬碟空間。關於ADO的網頁在:
http://www.microsoft.com/data/ado/adoinfo.htm.
在這裡你可以找到許多關於ADO的示例代碼和文章,尤其是在"Workshop"系列的文章中。你也可以從本站下載ADO2.5的幫助檔案。
儘管OLE DB SDK提供自己的ADO幫助檔案,你會發現ADO1.0的幫助檔案更易於使用。同時它還向你提供ADO對象模型的圖示
四、ADO是如何組織起來的?
以前的對象模型,如DAO和RDO是層次型的。也就是說一個較低的數據對象如Recordset是幾個較高層次的對象,如Environment和QueryDef,的子對象。在創建一個QueryDef對象的實例之前,你不能創建DAO Recordset對象的實例。但ADO卻不同,它定義了一組平面型頂級對象.
最重要的三個ADO對象是Connection, Recordset和Command. 本文將主要介紹Connection和Recordset這兩個對象。每個Connection的屬性定義了與數據源的連線。Recordset對象接收來自數據源的數據。Recordset可以與Connection一起起使用,先建立一個連線,然後獲取數據。儘管如此,Recordset也可以被單獨創建,其Connection參數可以在Open屬性定義。
五、ADO 2.0有什麼新特點?
對於ADO1.5以前包括1.5的版本來說,從功著你可以通過這兩種方法解決同樣的問題;它不是指存在重命名的或者最佳化的功能相同的對象.因此,移植到ADO不是一個簡單的事情.從另一方面來說,一旦你熟練掌握了RDO或DAO技術的話,學習ADO是件相當容易的事情.
ADO 2.0的新特性包括事件處理,記錄集的延續,分層目錄結構指針和數據成形,分散式事務處理,多維數據,遠程數據服務(RDS),以及對C++和Java的支持的增強.在鑽研一些Visual Basic代碼的時候將會見到所有的這些特性.當使用Visual J++時,我將舉例說明新的Windows Foundation Classes(WFC)是如何支持ADO的.ADO的最讓人激動的是在Visual Studio 6.0中的任何開發工具中你都可以找到對它的充分的支持.
六、ADO 對象編程模型
連線數據源 (Connection),可選擇開始事務。
可選擇創建表示 SQL 命令的對象 (Command)。
可選擇指定列、表以及 SQL 命令中的值作為變數參數 (Parameter)。
執行命令(Command、Connection 或 Recordset)。
如果命令以行返回,將行存儲在存儲對象中 (Recordset)。
可選擇創建存儲對象的視圖以便進行排序、篩選和定位數據 (Recordset)。
編輯數據。可以添加、刪除或更改行、列 (Recordset)。
在適當情況下,可以使用存儲對象中的變更對數據源進行更新 (Recordset)。
在使用事務之後,可以接受或拒絕在事務中所做的更改。結束事務 (Connection)。
七、如何使用ADO?
一旦安裝了ADO,在VB的工程->引用對話框中你就可以看到象下圖所示的東西了:
選擇 "ActiveX Data Objects 1.5 Library" (ADODB).在其下的 "ADO Recordset 1.5 Library"是一個客戶端的版本(ADOR),它定義了有聚的數據訪問對象。ADOR 對於客戶端的數據訪問來說是足夠的了,因為你不需要Connection對象來建立與遠程數據源的聯繫。
如果你想要訪問更多的外部數據源,你需要安裝這些外部數據源自己的OLE DB Provider,就象你需要為新的資料庫系統安裝新的ODBC驅動程式一樣。如果該外部數據源沒有自己的OLE DB Provider,你就得使用OLE DB SDK來自己為這個外部數據源創建一個OLE DB Provider了。這已不是本文討論的範圍了。
示例
下面的示例代碼以Northwinds資料庫作為遠程數據源,然後用ADO來訪問它。首先在控制臺中打開“32位數據源”,單擊“添加”按鈕。在彈出的對話框中選擇 "Microsoft Access Driver (*.mdb)" 作為數據源驅動程式。
然後按下圖所示,在對話框中填寫下面的內容
選擇資料庫Northwinds所在路徑。單擊完成,退出ODBC設備管理器。
啟動一個新的VB工程,在窗體的Load事件中輸入下面的代碼:
Private Sub Form_Load()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
'Set Connection properties
cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
cn.ConnectionTimeout = 30
cn.Open
If cn.State = adStateOpen Then _
MsgBox "Connection to NorthWind Successful!"
cn.Close
End Sub
按F5運行程式,看看,一個訊息框彈出來告訴你連線成功了。請注意,這裡我特別註明了是ADODB.Connection,而不是ADOR.Connection,這樣做是為了將二者區分開(如果你引用了ADODB和ADOR的話,這樣做很有必要)。連線字元串看上去同RDO的連線字元串差不多。事實上,二者確實差不多。
如果我們要訪問一個SQL server資料庫,你的Connection代碼看上去應象下面所示:
'設定連線屬性cn.Provider = "MSDASQL"
cn.ConnectionString = "driver={SQL Server};" & "server=prod1;uid=bg;pwd=;database=main"
cn.Open
"Provider"屬性指向SQL Server的OLE DB Provider.
回到我們的示例程式,讓我們創建一個Recordset對象來訪問“Orders”表,並從該表的"ShipCountry"欄位中產生頭十個不重複的國家名。修改窗體Load事件中的代碼,讓它看上去象下面這樣。
Private Sub Form_Load()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sSQL As String
Dim sOut As String
Dim Count As Integer
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Set properties of the Connection.
cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
cn.ConnectionTimeout = 30
cn.Open
If cn.State = adStateOpen Then _
MsgBox "Connection to NorthWind Successful!"
sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"
Set rs = cn.Execute(sSQL)
'Enumerate the recordset
sOut = ""
For Count = 1 To 10
sOut = sOut & rs("ShipCountry") & vbCrLf
rs.MoveNext
Next Count
MsgBox sOut, vbExclamation, "ADO Results"
cn.Close
End Sub
運行程式後,你會看到如下圖所示的訊息框。
不幸的是,目前這個Recrodset對象是唯讀的和forward cursor。如果你想要獲取更多的功能,你需要創建一個獨立的Recordset對象,該對象擁有自己的Connection屬性,就象下面的代碼所示:
Private Sub Form_Load()
Dim rs As ADODB.Recordset
Dim sSQL As String
Dim sOut As String
Dim Count As Integer
Set rs = New ADODB.Recordset
sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"
rs.Open sSQL, "DSN=RDC Nwind;UID=;PWD=;", adOpenDynamic
'Report Recordset Connection information
MsgBox rs.ActiveConnection, , "Connection Info"
'Enumerate the recordset
sOut = ""
For Count = 1 To 10
sOut = sOut & rs("ShipCountry") & vbCrLf
rs.MoveNext
Next Count
MsgBox sOut, vbExclamation, "ADO Results"
rs.Close
End Sub
上面代碼返回的結果同前例一樣,但是本代碼中的Recordset是獨立的。這一點是DAO和RDO做不到的。Recordset對象的Open方法打開一個代表從SQL查詢返回的記錄的游標。雖然你可以用Connection對象同遠程數據源建立連線,但請記住,在這種情況下,Connection對象和Recordset對象是平行的關係。
總結
本文僅向你介紹了ADO強大的功能的冰山一角。微軟承諾,在將來ADO將會取代DAO和RDO。所以現在你應該考慮如何將你的數據訪問代碼投向ADO的懷抱。這種轉變不會很痛苦,因為ADO的語法同現有的語法差不多。也許微軟或第三方會在將來開發出轉換嚮導來簡化這一轉換過程。從現在起,你就應開發純ADO代碼的程式。你也可以繼續使用DAO或RDO代碼來開發你的程式,但落伍的感覺總是不好的。
ADO(ActiveX Data Objects)是基於組件的資料庫編程接口,它是一個和程式語言無關的COM組件系統。本文主要介紹用ADO編程所需要注意的技巧和在VC下進行ADO編程的模式,並對C++Extensions進行了簡單的討論,希望對ADO開發人員有一定的幫助作用。因為ADO是一個和程式語言無關的COM組件系統,所以這裡討論的要點適用於所有的程式語言和編程環境,比如:VB、VBScript、VC、Java等等。
編程技巧
1.顯式定義對象類型
實際上,這條準則不僅適用於ADO編程,也適用於其他的與COM對象相關的編程。因為如果一開始就定義變數類型,則編譯器在編譯的時候就可以知道變數的類型,此時編譯器實際上是採用vtable偏移的方式來得到具體的COM對象包含的方法的地址(這一點和C++中虛函式的地址獲取方式類似);但如果一開始不指定變數類型的話,比如簡單地採用如下的語句:
DIM myCon as Object
或者是:
DIM myCon
這樣,編譯器在編譯的時候就不能得到變數的類型,而只能在運行的時候動態地得到方法的信息(通過使用接口IDispatch的Invoke方法來實現),如此為了得到方法的地址和相關的變數情況就需要在內部進行兩次調用,無疑會降低程式的運行速度。
2.綁定列到具體的欄位對象
在程式開始時就建立對欄位對象的引用,可以避免在每次得到記錄後,再在Recordset::Fields中進行查找而增加系統的開銷。
例如,可以採用如下所示的代碼:
Private Sub TblBrowse_Click()
Dim fld1 As ADODB.Field
Dim fld2 As ADODB.Field
Dim rs As ADODB.Recordset
set rs=g_cn.execute(...)
'g_cn為全局對象adodb.connection
Set fld1 = rs.Fields(“id”) '數據表的欄位
Set fld2 = rs.Fields(“name”) ’數據表的欄位
If rs.BOF = False Then
While rs.BOF = False
Debug.Print fld1.Value
Debug.Print fld2.Value
rs.MoveNext
Wend
End If
rs.Close
End Sub
3.用SQL語句和存儲過程進行數據更新
儘管採用Recordset對象來更新數據是非常方便的,但是它的開銷也大,通過數據源對象返回的查詢集不僅包含了數據,而且也包含了元數據(metadata),在有些時候元數據可能比數據本身還要大,所以最好採用SQL語句來更新數據。還有要使用存儲過程而不是單一的SQL語句來獲取信息。因為存儲過程是在伺服器端執行的,只把結果返回到客戶端,這樣一方面可以降低網路進行數據互動的開銷,另一方面使系統更加容易維護,並且能保持數據的一致性。
4.使用集合操作單條的SELECT語句
在使用游標時,最好使用集合的方法對單條的SELECT語句進行操作。Recordset::get_Collect方法和Recordset::put_Collect方法是Recordset 對象的捷徑,可以快速地得到一個欄位的值而不需要獲得關於一個欄位的引用。例如,可以採用如下代碼:
Sub Collect()
Dim rs As New Recordset
rs.ActiveConnection = “...”
rs.Source=“一條SQL查詢語句”
rs.Open
Debug.Print rs.Collect(0),rs.Collect(1),rs.Collect(2)
Debug.Print rs!au_id, rs!au_fname, rs!au_lname
End Sub
5.只查詢所需要的數據
儘管很多開發人員都習慣採用“SELECT * FROM TBL”的模式進行查詢,但是為了提高系統的效率,如果只需要其中某幾個欄位的值,最好把這幾個欄位直接寫出來,同時需要限定返回記錄集的範圍(通過WHERE子句進行限定)。
6.正確選擇游標的位置、類型和鎖方式
如果只需要按順序讀取記錄並且不需要滾動和更新記錄,最好使用伺服器端游標(adUseServer)、僅向前游標(adOpenForwardOnly)和讀加鎖(adLockReadOnly),這樣可以獲得最好的性能。如果需要滾動記錄,採用客戶端游標(adUseServer)會比採用伺服器端游標所得到的性能要好,因為ADO系統默認是採用伺服器端游標類型。當然如果數據集合相當大,採用伺服器端游標的性能會好一些。同時需要注意:如果採用客戶端游標,最好只採用讀加鎖(adLockReadOnly)的鎖類型,因為如果需要更新數據,客戶端游標引擎需要得到額外的信息(元數據),而獲取這個信息的代價是非常昂貴的。
7.調整記錄集對象的CacheSize屬性
ADO使用記錄集對象的CacheSize屬性來決定提取和快取的記錄的數目,當在快取的範圍內瀏覽數據時,ADO就只從快取中提取數據。當要瀏覽的數據超出快取範圍的時候,ADO就釋放當前快取,提取下一些記錄(提取的數目為CacheSize所指定的大小),所以必須根據具體的應用程式的情況,來設定CacheSize的大小,保證得到最佳的性能。
8.定義Command對象的參數
在許多數據源中,得到參數信息和執行命令的代價幾乎是一樣的,所以最好自己在程式中定義好Command參數(也就是說要定義好參數的名稱、類型和方向信息),避免一些從數據提供者(Provider)那裡獲取信息的操作。
9.使用原始的OLE DB提供者
MDAC對許多數據源提供了原始的數據提供者,比如SQL Server、Oracle和Access資料庫,這樣就不需要再通過ODBC來獲取數據(也就是說不需要再通過ODBC驅動這一層),這樣的好處是能更快地得到數據,並且能降低磁碟和記憶體的開銷。
10.斷開Connection連線
如果使用客戶端游標,就要斷開Connection連線。ADO有一個特徵是當使用客戶端游標操作Recordset記錄集的時候,不需要和伺服器保持聯繫。所以可以充分利用這個特性降低伺服器端的開銷(伺服器就不需要維護這些連線了)。當操作完記錄集需要更新時,可以重新和資料庫進行連線來更新數據。為了創建一個可以下線的記錄集,同時需要使用靜態游標(adOpenStatic)和批處理的加鎖模式(adLockBatchOptimistic)。下面是有關處理的VC代碼:
pRs.CreateInstance(__uuid(Recordset));
pRs->CursorLoction=adUseClient;
pRs->Open(strCmdText,strConnection,adOpenStatic,adLockBatchOptimistic,adCmdText);
pRs->PutRefActiveConnection(NULL);
//對記錄集對象pRs進行操作
//重新和資料庫建立連線
pRs->PutRefActiveConnectio(pCon);
//批量更新數據
pRs->UpdateBatch(adAffectAll);
需要注意的是:當執行批量更新時,必須自己處理數據衝突問題,因為更新數據時,其他用戶也可能同時正在對該數據進行操作。
11.使用adExecuteNoRecords選項
如果不需要返回記錄,要使用adExecuteNoRecords選項。ADO 2.0包括一個新的執行選項稱為adExecuteNoRecords。當使用該選項的時候,ADO就不會創建記錄集對象,不設定任何游標屬性。數據提供者因為不需要認證集合的屬性而使性能得到最佳化。具體的例子如下:
con.Execute “insert into tbl values(fv1, fv2) ”, , adExecuteNoRecords
對僅有一條的執行語句採用Connection::Execute方法比使用Recordset::Open方法或者是Command::Execute方法的效果要好,因為ADO不保留任何命令狀態的信息,因此執行性能就有所改進。
12.使用session/connection緩衝池
因為資料庫的打開和關閉非常消耗系統資源,因此,使用連線池對基於多層的套用的性能會有很大的提高。當使用MDAC的時候,開發人員本身並不需要考慮對資料庫連線的快取,MDAC會自動處理它。連線池在兩個層次上提供支持:OLE DB sessions和ODBC連線。如果使用ADO,資料庫連線會自動被OLE DB session緩衝池所快取;如果使用ODBC,可以利用在ODBC數據源管理中新的連線緩衝池選項對ODBC緩衝進行設定。
實現方法
我們知道,在VB下進行基於ADO的編程相對比較簡單,只要通過reference載入了適當的類型庫後,就可以正常地調用ADO對象。但是對於VC下的基於ADO的資料庫開發就稍微複雜一些。VC中實現對ADO操作通常有三種方法: