我使用ActiveX Data Object(ADO)是從1.5版本開始,那已經(jīng)是一個(gè)非常古老的版本了。現(xiàn)在的版本中,許多東西都發(fā)生了變化。從每一次版本升級(jí)中我都學(xué)到許多新的東西。這些東西你不能全部從書本上找到,或者至少可以說,不能從一個(gè)地方找到。
我在這里精心選擇和總結(jié)了這些ADO開發(fā)要點(diǎn)和技巧。其中有些問題可能就是你一直念念不忘的問題;有些是你從來不曾了解的技術(shù);還有一些只是分門別類地展示ADO開發(fā)的知識(shí)精華。
一、共享連接對(duì)象
把連接字符串傳遞給Command、Recordset或者Record對(duì)象時(shí),每次你都是在隱含地命令A(yù)DO創(chuàng)建一個(gè)Connection對(duì)象:
Dim rec1 As ADODB.Record
Dim rec2 As ADODB.Record
Dim rec3 As ADODB.Record
Set rec1 = New ADODB.Record
rec1.Open "localstart.asp", "URL=http://localhost/"
Set rec2 = New ADODB.Record
rec2.Open "global.asa", "URL=http://localhost/"
Set rec3 = New ADODB.Record
rec3.Open "iisstart.asp", "URL=http://localhost/"
' 執(zhí)行一些操作
rec1.Close
rec2.Close
rec3.Close
Set rec1 = Nothing
Set rec2 = Nothing
Set rec3 = Nothing
為了節(jié)省資源,你應(yīng)該先創(chuàng)建一個(gè)Connection對(duì)象,然后把它傳遞給所有要求活動(dòng)連接的對(duì)象。也就是說,上面的代碼應(yīng)該改成下面這種形式:
Dim con As ADODB.Connection
Dim rec1 As ADODB.Record
Dim rec2 As ADODB.Record
Dim rec3 As ADODB.Record
Set con = New ADODB.Connection
con.Open "URL=http://localhost/"
Set rec1 = New ADODB.Record
rec1.Open "localstart.asp", con
Set rec2 = New ADODB.Record
rec2.Open "global.asa", con
Set rec3 = New ADODB.Record
rec3.Open "iisstart.asp", con
' 執(zhí)行一些操作'
rec1.Close
rec2.Close
rec3.Close
con.Close
Set rec1 = Nothing
Set rec2 = Nothing
Set rec3 = Nothing
Set con = Nothing
二、讀取ConnectionString屬性
從任何已經(jīng)打開的Connection對(duì)象中,包括由Recordset、Command、或者Record對(duì)象的ActiveConnection屬性返回的Connection對(duì)象,你總是可以讀取到ConnectionString屬性。
Dim com As ADODB.Command
Dim rst As ADODB.Recordset
Set com = New ADODB.Command
com.ActiveConnection = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=NWind.mdb;"
com.CommandText = "SELECT * FROM Customers"
Set rst = com.Execute
MsgBox com.ActiveConnection.ConnectionString
rst.Close
Set rst = Nothing
Set com = Nothing
上述代碼運(yùn)行時(shí),你將從消息框看到如下輸出:
Provider=Microsoft.Jet.OLEDB.4.0;
Password="";
User ID=Admin;
Data Source=NWind.mdb;
Mode=Share Deny None;
Extended Properties="";
Jet OLEDB:System database="";
Jet OLEDB:Registry Path="";
Jet OLEDB:Database Password="";
Jet OLEDB:Engine Type=4;
Jet OLEDB:Database Locking Mode=0;
Jet OLEDB:Global Partial Bulk Ops=2;
Jet OLEDB:Global Bulk Transactions=1;
Jet OLEDB:New Database Password="";
Jet OLEDB:Create System Database=False;
Jet OLEDB:Encrypt Database=False;
Jet OLEDB:Don't Copy Locale on Compact=False;
Jet OLEDB:Compact Without Replica Repair=False;
Jet OLEDB:SFP=False
現(xiàn)在你就可以分析這個(gè)字符串,找出有關(guān)該連接的特定信息,比如當(dāng)數(shù)據(jù)庫(kù)被壓縮時(shí)它是否會(huì)被加密(Jet OLEDB:Encrypt Database屬性)。
三、使用動(dòng)態(tài)屬性
Connection對(duì)象的Properties集合可用來設(shè)置供應(yīng)商特有的選項(xiàng),比如SQL Server的OLE DB驅(qū)動(dòng)程序的Prompt動(dòng)態(tài)屬性。
Dim con As ADODB.Connection
Set con = New ADODB.Connection
con.Provider = "SQLOLEDB"
con.Properties("Prompt") = adPromptAlways
con.Open
' 提示用戶選擇數(shù)據(jù)庫(kù)'
con.Close
Set con = Nothing
上述代碼運(yùn)行時(shí),用戶將看到一個(gè)對(duì)話框,這個(gè)對(duì)話框允許用戶選擇要登錄到哪一個(gè)數(shù)據(jù)庫(kù)。
四、明智地選擇游標(biāo)位置
選擇游標(biāo)的位置時(shí),你必須考慮對(duì)于當(dāng)前連接來說哪些服務(wù)比較重要。
如果數(shù)據(jù)提供者的服務(wù)正是你所需要的,你應(yīng)該使用服務(wù)器端游標(biāo)。這些服務(wù)是數(shù)據(jù)源驅(qū)動(dòng)程序提供的服務(wù),它們通常具有非常好的可伸縮性。另外,通過保留服務(wù)器端游標(biāo),你無需象使用客戶端游標(biāo)那樣總是把全部的數(shù)據(jù)發(fā)送到客戶端。
另一方面,本地游標(biāo)服務(wù),例如Microsoft數(shù)據(jù)形狀服務(wù)for OLE DB,能夠提供一些客戶端游標(biāo)特有的服務(wù)。要讓這些服務(wù)能夠起作用,數(shù)據(jù)必須發(fā)送到本地機(jī)器上,正如數(shù)據(jù)形狀服務(wù)所要求的一樣。
你可以用Connection.CursorLocation屬性設(shè)置游標(biāo)的位置,但選擇應(yīng)該明智、慎重。
五、明智地選擇游標(biāo)類型
選擇游標(biāo)的類型與選擇游標(biāo)的位置同樣重要。游標(biāo)共有四種類型,每一種類型都有各自的優(yōu)點(diǎn)和缺點(diǎn)。
Static游標(biāo)(靜態(tài)游標(biāo))提供了數(shù)據(jù)在給定時(shí)刻的一個(gè)快照。在這種類型的游標(biāo)中,數(shù)據(jù)改動(dòng)(包括其他用戶的數(shù)據(jù)增加或者刪除操作)總是不可見。static游標(biāo)用來制作報(bào)表很理想,因?yàn)橹谱鲌?bào)表需要有數(shù)據(jù)的一個(gè)一致的、不會(huì)變化的視圖,但static游標(biāo)不一定速度最快。由于數(shù)據(jù)的改變不會(huì)顯示出來,對(duì)于每一個(gè)使用static游標(biāo)的連接,服務(wù)提供者必須分別為它創(chuàng)建和維護(hù)一份給定時(shí)刻的數(shù)據(jù)副本。
Forward Only游標(biāo)(只能向前的游標(biāo))與靜態(tài)游標(biāo)基本相同,不同之處在于你只能向前移動(dòng)訪問數(shù)據(jù),但不能向后。與Static游標(biāo)相比,這個(gè)限制有利于提高性能,但它仍舊要求數(shù)據(jù)源維護(hù)一個(gè)數(shù)據(jù)的臨時(shí)副本,使得其他用戶對(duì)數(shù)據(jù)的改動(dòng)不會(huì)影響你的數(shù)據(jù)。
Dynamic游標(biāo)(動(dòng)態(tài)游標(biāo))允許你看到其他用戶對(duì)數(shù)據(jù)的修改和刪除操作,而且你可以在整個(gè)記錄集之內(nèi)自由地移動(dòng)。與Static和Forward Only游標(biāo)不同,Dynamic游標(biāo)不要求數(shù)據(jù)源維護(hù)一份數(shù)據(jù)的靜態(tài)映像,因此Dynamic游標(biāo)要比前兩種游標(biāo)快。
最后一種游標(biāo)類型是Keyset游標(biāo)(鍵集游標(biāo))。Keyset游標(biāo)與Dynamic游標(biāo)非常相似,不同之處在于你不能看到其他用戶新增的記錄。在Keyset游標(biāo)中,其他用戶刪除的記錄也將不可訪問。和Dynamic游標(biāo)一樣,Keyset游標(biāo)中你也可以看到其他用戶的修改。Keyset游標(biāo)可能要比Dynamic游標(biāo)快,這是因?yàn)镵eyset游標(biāo)不需要經(jīng)常地去檢查是否有新記錄加入、是否有記錄被刪除(因?yàn)樾略龅挠涗洸豢梢?,被刪除的記錄變成不可訪問)。
考慮每一個(gè)理由,然后再選擇適合你的游標(biāo)類型。
六、手工構(gòu)造參數(shù)
當(dāng)性能因素很重要時(shí),請(qǐng)手工定義參數(shù):
Dim con As ADODB.Connection
Dim com As ADODB.Command
Dim par As ADODB.Parameter
Dim rst As ADODB.Recordset
Set con = New ADODB.Connection
con.Open "Provider=SQLOLEDB;" & "Server=localhost;" _
& "Initial Catalog=Northwind;" & "User ID=sa;"
Set com = New ADODB.Command
Set com.ActiveConnection = con
Set par = com.CreateParameter ("CategoryName", adVarWChar, _
adParamInput, 15)
com.Parameters.Append par
Set par = com.CreateParameter ("OrdYear", adVarWChar, _
adParamInput, 4)
com.Parameters.Append par
com.CommandText = _
"EXECUTE SalesByCategory 'Produce', '1997'"
Set rst = com.Execute
' 執(zhí)行一些操作'
rst.Close
con.Close
Set com = Nothing
Set rst = Nothing
Set con = Nothing
采用手工方式定義參數(shù)之后,ADO不必為了找出存儲(chǔ)過程的參數(shù)列表而去查詢數(shù)據(jù)源。當(dāng)用戶只執(zhí)行一個(gè)查詢過程且對(duì)存儲(chǔ)過程執(zhí)行時(shí)間要求不高時(shí),這一點(diǎn)不是很重要;但是,如果用戶要執(zhí)行大量的存儲(chǔ)過程,而且希望能夠立即得到答案,那么這一點(diǎn)就很重要了。
七、用Stream對(duì)象構(gòu)造緩存
Stream對(duì)象可以在沒有物理數(shù)據(jù)源的情況下使用。你可以利用這個(gè)對(duì)象在本地機(jī)器的內(nèi)存中創(chuàng)建緩存。用法很簡(jiǎn)單,只需先創(chuàng)建Stream對(duì)象的實(shí)例,然后就可以開始寫入數(shù)據(jù):
Dim str As ADODB.Stream
Set str = New ADODB.Stream
str.Open
str.WriteText "這是文本信息,"
str.WriteText "我們希望它保留在"
str.WriteText "內(nèi)存中。", adWriteLine
str.WriteText "這是第二"
str.WriteText "行", adWriteLine
MsgBox "緩存中共有" & _
str.Size & "個(gè)字符"
str.Position = 0
MsgBox "緩存內(nèi)容: " & str.ReadText
str.Close
另外,你還可以用Stream對(duì)象處理二進(jìn)制數(shù)據(jù),只需用Write和Read方法取代操作文本的WriteText和ReadText方法。把數(shù)據(jù)放入緩存之后,你可以用SaveToFile方法永久保存數(shù)據(jù)。
八、檢查警告信息
Connection對(duì)象的Errors集合不僅用來報(bào)告數(shù)據(jù)提供者在執(zhí)行某個(gè)操作時(shí)出現(xiàn)的錯(cuò)誤,而且它還用于指示執(zhí)行操作過程中出現(xiàn)的非致命性警告信息。
Connection.Open、Recordset.CancelBatch、Recordset.Resync以及Recordset.UpdateBatch方法,還有Recordset.Filter屬性,都有可能產(chǎn)生警告信息。
要檢測(cè)數(shù)據(jù)提供者的警告信息(或錯(cuò)誤信息),請(qǐng)?jiān)谑褂蒙鲜鋈魏畏椒▎?dòng)某個(gè)操作之前調(diào)用Connection.Errors.Clear方法;操作完成后,用Errors集合的Count屬性檢查是否存在任何警告信息。
九、事務(wù)嵌套
使用Jet OLE DB provider時(shí),你可以嵌套事務(wù),最多五層。使用多層事務(wù)將賦予你空前的數(shù)據(jù)控制能力。
Dim con As ADODB.Connection
Dim iLevel As Integer
Set con = New ADODB.Connection
con.CursorLocation = adUseClient
con.Open "Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=NWind.mdb;"
con.BeginTrans
' 改動(dòng) 1
con.BeginTrans
' 改動(dòng) 2
con.BeginTrans
' 改動(dòng) 3
iLevel = con.BeginTrans
' 改動(dòng) 4
MsgBox "Level " & iLevel
con.CommitTrans
con.RollbackTrans
con.CommitTrans
con.CommitTrans
con.Close
Set con = Nothing
在上面這個(gè)例子中,改動(dòng)1和2將成功,改動(dòng)3和4無效。改動(dòng)4表面上已經(jīng)被提交,但由于第三層事務(wù)回退,從而導(dǎo)致所有它里面的事務(wù)都被回退。
十、重視數(shù)據(jù)形狀
我要為你介紹的最后一則技巧是不要輕視Microsoft Data Shaping Service for OLE DB的力量。Data shaping(數(shù)據(jù)形狀)允許你聚合多個(gè)SQL語句,構(gòu)造出層次型的記錄集。在層次型記錄集中,單個(gè)字段能夠指向整個(gè)子記錄集。
例如,如果有兩個(gè)來自Biblio數(shù)據(jù)庫(kù)的表Publishers和Titles(Biblio數(shù)據(jù)庫(kù)是Microsoft的一個(gè)示例,可以從這里下載),你可以按照下面介紹的方式構(gòu)造SQL命令,把它們連接到一個(gè)記錄集。
SELECT Publishers.Name, Titles.Title
FROM Publishers
INNER JOIN Titles ON
Publishers.PubID=Titles.PubID
ORDER BY Publishers.Name, Titles.Title;
前面幾個(gè)記錄如下所示:
Name (Pub) Title
-------------- -----------------------------
A K PETERS A Physical Approach to Col...
A K PETERS Colour Principles for C...
A SYSTEM PUBNS C Plus Plus Reference Card
A SYSTEM PUBNS C Reference Card
AA BALKEMA Planning With Linear Progr...
AARP Thesaurus of Aging Termin...
ABACUS Access 2.0 Programming Bible
ABACUS Advanced Access Programming
可以看到,這個(gè)記錄集中存在大量的重復(fù)數(shù)據(jù)。利用數(shù)據(jù)形狀技術(shù),我們能夠極大地減小結(jié)果數(shù)據(jù)的規(guī)模大小。下面的表被發(fā)送到客戶端,并傳遞給數(shù)據(jù)形狀游標(biāo)服務(wù)。
Name (Publisher)
------------------------------------
A K PETERS
A SYSTEM PUBNS
AA BALKEMA
AARP
ABACUS
Title
------------------------------------
A Physical Approach to Color...
Colour Principles for Computer...
C Plus Plus Reference Card
C Reference Card
Planning With Linear Programming
Thesaurus of Aging Terminology : ...
Access 2.0 Programming Bible
Advanced Access Programming
在數(shù)據(jù)形狀游標(biāo)服務(wù)中,這兩個(gè)表通過Chapters字段類型連接成一個(gè)層次結(jié)構(gòu),Chapters字段類型用來訪問子記錄集。
Dim con As ADODB.Connection
Dim rstPubs As ADODB.Recordset
Dim rstTitles As ADODB.Recordset
Dim sShape As String
Set con = New ADODB.Connection
Set rstPubs = New ADODB.Recordset
con.Provider = "MSDataShape"
con.Open "Data Provider=Microsoft.Jet.OLEDB.4.0;" _
& "Data Source=Biblio.mdb;"
sShape = "SHAPE {SELECT Name, PubID " _
& " FROM Publishers} " _
& " APPEND ({SELECT Title, PubID " _
& " FROM Titles} " _
& " As PubTitles " _
& " RELATE PubID TO PubID) "
rstPubs.Open sShape, con
Do Until (rstPubs.EOF)
Debug.Print rstPubs!Name
Set rstTitles = rstPubs("PubTitles").Value
Do Until (rstTitles.EOF)
Debug.Print " " & rstTitles!Title
rstTitles.MoveNext
Loop
rstPubs.MoveNext
Loop
rstPubs.Close
con.Close
Set rstPubs = Nothing
Set con = Nothing
運(yùn)行上面的代碼時(shí),我們將看到如下輸出:
A K PETERS
A Physical Approach to Color...
Colour Principles for Computer...
A SYSTEM PUBNS
C Plus Plus Reference Card
C Reference Card
AA BALKEMA
Planning With Linear Programming
AARP
Thesaurus of Aging Terminology : ...
ABACUS
Access 2.0 Programming Bible
Advanced Access Programming
可以看到,數(shù)據(jù)形狀的功能非常強(qiáng)大。