直播中
Source
數(shù)據(jù)源??梢允菙?shù)據(jù)庫中的表名、存儲(chǔ)的查詢或過程、SQL字符串、Command對象或適用于提供者的其他命令對象
ActiveConnection
記錄集使用的連接??梢允且粋€(gè)連接字符串或者一個(gè)打開的Connection對象
CursorType
使用的光標(biāo)類型。必須是定義的光標(biāo)類型中的一種,缺省值為adForwardOnly
LockType
使用的鎖定類型。必須是定義的鎖定類型中的一種,缺省值為adLockReadOnly
Options
告訴提供者Source參數(shù)的內(nèi)容是什么,如表、文本字符串等等
例如,要打開數(shù)據(jù)庫pubs中authors表上的記錄集:
Dim rsAuthors
Set rsAuthors = Server.CreateObject("ADODB.Recordset")
rsAuthors.Open "authors", strConn
' Do something here
rsAuthors.Close
Set rsAuthors = Nothing
注意,有幾個(gè)參數(shù)沒有指定。實(shí)際上,所有的參數(shù)都是可選的,可以在打開記錄集之前為它們設(shè)置相應(yīng)的屬性值:
Dim rsAuthors
Set rsAuthors = Server.CreateObject("ADODB.Recordset")
With rsAuthors
.Source = "authors"
.ActiveConnection = strConn
.CursorType = adOpenForwardOnly
.LockType = adLockReadOnly
.Open
End With
' Do something here
rsAuthors.Close
Set rsAuthors = Nothing
一旦打開記錄集,當(dāng)前指針自動(dòng)地位于第一條記錄上。如果在記錄集中沒有記錄,那么EOF和BOF屬性都是True:
rsAuthors.Open "authors", strConn
If rsAuthors.BOF and rsAuthors.EOF Then
' Recordset is empty
End If
1. Options參數(shù)
Open方法的Options參數(shù)允許指定命令文本內(nèi)容。它可以是以下CommandTypeEnum常數(shù)之一:
· adCmdText:文本命令,比如SQL字符串。
· adCmdTable:表名。
· adCmdStoredProc:存儲(chǔ)過程名。
· adCmdFile:保存的記錄集的文件名。
· adCmdTableDirect:表名。
· adCmdURLBind:URL地址。
adCmdTable與adCmdTableDirect的區(qū)別很小,如果想使用表中的全部列,使用adCmdTableDirect將由于ADO執(zhí)行了某些內(nèi)部優(yōu)化而使運(yùn)行速度變得稍快一些。
如果沒有指定命令的類型,ADO必須推算出執(zhí)行的命令的類型,這將導(dǎo)致額外的開銷。
這里還有兩個(gè)選項(xiàng):adCmdUnspecified表示沒有指定類型;adCmdUnknow表示命令的類型未知。一般地可能不會(huì)使用它們。
額外的選項(xiàng)
Options參數(shù)可以是以上常數(shù)中的任一個(gè),但也可以加入下列ExecuteOptionEnum常數(shù):
· adAsyncExcute:異步地執(zhí)行命令。
· adAsyncFetch:取得初始的行集后,異步地獲取剩下的行。
· adAsyncFetchBlocking:除了獲取記錄不阻止命令運(yùn)行以外,其他與adAsyncFetch相似。
· adExechteNoRecords:命令不返回任何記錄。
異步處理意味著在后臺(tái)執(zhí)行操作,可以運(yùn)行命令,然后繼續(xù)其他工作,而不需要等待其執(zhí)行完畢(同步操作)。當(dāng)創(chuàng)建用戶界面時(shí),這顯得特別方便,因?yàn)榭梢詮拿顖?zhí)行中返回,向用戶顯示一些內(nèi)容,而同時(shí)數(shù)據(jù)的獲取仍然在后臺(tái)進(jìn)行。當(dāng)返回記錄集時(shí),這對ASP程序員來說不是很有用,因?yàn)槟_本語言不支持ADO事件,所以記錄集何時(shí)已完成填充移無法得知。當(dāng)處理更新、刪除或插入數(shù)據(jù)命令以及不返回記錄集的時(shí)候,可以使用異步操作,即僅在不關(guān)心結(jié)果的情況下才能使用。
在另一方面,adExecuteNoRecords選項(xiàng)十分有用。它告訴ADO執(zhí)行的命令不返回任何數(shù)據(jù)。所以,就沒有必要?jiǎng)?chuàng)建記錄集(總之,可能為空)。這會(huì)加速正在運(yùn)行的更新或添加數(shù)據(jù)的查詢操作。
為了加入這些選項(xiàng)之一,可以使用Or符號(等同于加號“+”)
adCmdStoredProc Or adExecuteNoRecords
adCmdStoreProc + adExecuteNoRecords
在下一章,將看到對相關(guān)內(nèi)容更詳細(xì)的介紹,因?yàn)檫@在處理命令(而不是記錄集)時(shí)會(huì)更有用。
2. 在記錄集中移動(dòng)
一旦打開一個(gè)記錄集,經(jīng)常需要遍歷每一條記錄。這需要使用EOF屬性。當(dāng)?shù)竭_(dá)記錄集的末尾時(shí),EOF就變?yōu)門rue,因?yàn)榭梢赃@樣創(chuàng)建一個(gè)循環(huán):
rsAuthors.Open "authors", strConn
While Not rsAuthors.EOF
Response.Write rsAuthors("au_lname:) & ", " & _
rsAuthors("au_fname") & "<BR>"
rsAuthors.MoveNext
Wend
上面的例子一直循環(huán)到EOF屬性為True時(shí)才退出。MoveNext方法用于移到下一條記錄。
如果記錄集允許向后移動(dòng),則可以使用MovePrevious方法。在這種情況下,循環(huán)中需要檢測BOF屬性值。另外分別還有移動(dòng)到第一條和最后一條記錄的MoveFirst和MoveLast方法:
rsAuthors.Open "authors", strConn, adOpenDynamic
' Now on first record
rsAuthors.MoveLast
' Now on last record
rsAuthors.MovePrevious
rsAuthors.MovePrevious
' Now three rows from the end of the recordset
rsAuthors.MoveFirst
' Back at the beginning again
3. 使用Fields集合
Fields集合包含記錄集中每一字段(列)的Fields對象。Fields集合是記錄集的缺省集合,因此在訪問字段時(shí)可以省略,就如同上面的While...Wend例子中的情況。因此,有多種訪問字段的方法:
rsAuthors.Fields("au_lname").Value
rsAuthors("au_lname).Value
rsAuthors(1).Value
rsAuthors.Fields(1).Value
可以使用字段名,或使用它在集合中的位置。使用名字是最好的,因?yàn)檫@樣將使代碼更易于維護(hù)。
Value屬性是字段的缺省屬性,因此也可以省略,比如:
rsAuthors("au_lname")
如果想遍歷所有字段,可以使用For Each結(jié)構(gòu):
For Each fldAuthor In rsAuthors.Fields
Response.Write fldAuthor.Name & " : " & _
fldAuthor.Value & "<BR>"
Next
這個(gè)例子將打印每一個(gè)字段的名字和值。
4. 書簽
當(dāng)在記錄集中移動(dòng)時(shí),可能需要保留記錄的位置,以后再移回來。同真實(shí)的書簽相似,一個(gè)記錄集書簽是一個(gè)指向單個(gè)記錄的唯一的指針。
為了使用書簽,只需將Bookmark屬性值賦予一個(gè)變量:
varBkmk = rsAuthors.Bookmark
然后,可以在記錄集中移動(dòng),以后可以通過相反的命令將記錄移到做過書簽標(biāo)記的相應(yīng)記錄上:
rsAuthors.Bookmark = varBkmk
在記錄集中查找記錄時(shí),書簽是非常有用的。在本章稍后的8.4.5節(jié)中有一個(gè)相關(guān)的例子。
注意,并非所有記錄集都支持書簽,Supports方法(在下面討論)將能識(shí)別其是否支持書簽。
值得注意的重要一點(diǎn)是,不能跨越不同的記錄集使用書簽,即使這些記錄集是相同的命令創(chuàng)建的??紤]一下以下代碼:
rsAuthors.Open "authors", strConn
rsAuthorsOther.Opne "authors", strConn
varBkmk = rsAuthors.Bookmark
varBkmkOther = rsAuthorsOther.Bookmark
盡管兩個(gè)記錄集是用相同的命令創(chuàng)建的,但記錄集的書簽是不一樣的。
可以使用Clone方法獲得可交換的書簽,但在這里我們不討論它。
5. 支持的功能
如上所述,并非所有的記錄集都支持書簽。還有許多其他的記錄集選項(xiàng)也不是被所有的提供者或記錄集類型支持的,因此可以用Supports方法驗(yàn)證一下。
Supports方法使用一個(gè)或多個(gè)CursorOptionEnum值作為參數(shù),返回True或False表明是否支持該選項(xiàng)。這些值的列表相當(dāng)龐大,所以將其列于附錄F中。
例如:
If rsAuthors.Supports(adBookmark) Then
' The recordset supports bookmarks
varBkMk = rsAuthors.Bookmark
End If
可以使用Or或加號“+”組合多個(gè)常數(shù):
If rsAuthors.Supports(adBookmark Or adFind) Then
' The recordset supports bookmarks and use of Find
varBkMk = rsAuthors.Bookmark
End If
8.4.4 過濾記錄集
過濾是一種暫時(shí)地限定記錄集中可見記錄的一種方法。如果僅顯示記錄集中的某些記錄,但又不需要每次都重新查詢數(shù)據(jù)庫,這種方法非常有用。
1. 使用條件過濾
Filter屬性擁有多個(gè)參數(shù),其中一個(gè)就是條件表達(dá)式,它非常像SQL中Where子句:
rsAuthors.Filter = "state = 'ca'"
這個(gè)語句限定記錄集只顯示州名為ca的記錄。使用這個(gè)過濾條件將使當(dāng)前指針回到第一條匹配記錄上??梢员闅v記錄集中的全部記錄,并且只有匹配條件的記錄才可見。
不僅僅限于單一條件,還可以使用And或Or把多個(gè)條件連接在一起:
rsAuthors.Filter = "au_lname = 'Homer' Or au_lname = 'Francis'"
這將過濾出姓為Francis或Homer的記錄。
上面的例子顯示了一個(gè)列匹配一個(gè)值的過濾方法,也可以使用下面操作符中的任何一種:
<:小于。
>:大于。
<=:小于等于。
>=:大于等于。
<>:不等于。
LIKE:通配符。
當(dāng)使用通過配符操作時(shí),可以使用“*”或“%”符號。例如:
rsAuthors.Filter = "au_lname LIKE 'Ho%'"
“*”或“%”作為一個(gè)通配符,匹配任何字符,因此上面的例子會(huì)匹配au_lname字段中以“Ho”字符開始的所有記錄。
可以使用空字符串清空過濾條件,這樣將顯示全部記錄:
rsAuthors.Filter = ""
2. 使用常數(shù)過濾
Filter屬性也能用FilterGroupEnum常數(shù)作為其參數(shù):
· adFilterNone:清空當(dāng)前過濾條件,與使用一個(gè)空字符串的效果相同。
· adeFilterPendingRecords:只顯示那些已改變的,但還沒送到服務(wù)器的記錄,只在成批更新模式下可用。
· adFilterAffectedRecords:只顯示那些受上一次調(diào)用Delete、Resync、UpdateBatch和CancelBatch方法影響的記錄。
· adFilterFetchedRecords:顯示高速緩存中的記錄,即上一次調(diào)用讀取記錄的命令時(shí)的結(jié)果。
· adFilterConflictingRecords:顯示在上一次成批更新中更新失敗的記錄。
稍后會(huì)看到關(guān)于成批更新的介紹。
3. 使用書簽過濾
最后一種過濾記錄集的方法是使用一個(gè)書簽數(shù)組??梢允褂眠@個(gè)技術(shù)創(chuàng)建一個(gè)記錄列表,然后再應(yīng)用一個(gè)過濾條件對其過濾。例如:
rsAuthors.Open "authors", strConn, adOpenKeyset, _
adLockReadOnly, adCmdTableDirect
' Save bookmark for the first record
avarBkmk(0) = rsAuthors.Bookmark
' Move forward two records
rsAuthors.MoveNext
rsAuthors.MoveNext
' Save bookmark for the third record
avarBkmk(1) = rsAuthors.Bookmark
' Move to the end and save the bookmark
rsAuthors.MoveLast
avarBkmk(2) = rsAuthors.Bookmark
' Now apply the filter
rsAuthors.Filter = Array(avarBkmk(0), avarBkmk(1), avarBkmk(2))
' Now loop through the recordset
While Not rsAuthors.EOF
Response.Write rsAuthors("au_lname") & "<BR>"
rsAuthors.MoveNext
Wend
當(dāng)循環(huán)至記錄集末尾位置時(shí),會(huì)發(fā)現(xiàn)只有三條記錄,因?yàn)橹挥腥齻€(gè)書簽應(yīng)用于過濾條件。
注意,不能直接使用數(shù)組avarBkmk,必須使用Array函數(shù)將各個(gè)書簽轉(zhuǎn)換成不同的數(shù)組。
8.4.5 查找記錄
查找單個(gè)的記錄由Find方法來完成。它類似于使用條件的過濾方法:
rsAuthors.Find "au_lname = 'Lloyd'"
它們之間最主要的區(qū)別在于這種方法只能有一個(gè)條件,不允許使用And或Or。
可以使用可選的參數(shù)指定一些額外的選項(xiàng),其完整的語法如下:
Recordset.Find Criteria, [SkipRows], [SearchDirection], [Strat]
SkipRows是一個(gè)數(shù)字,表示在開始查找記錄前跳過的行數(shù)。缺省為0,查詢從當(dāng)前行開始。
SearchDirection可以是adSearchForward,表示向前搜索記錄;或者adSearchBackward,表示向后搜索記錄。
Start是一個(gè)書簽,指出開始查找記錄的位置。
如果打開相應(yīng)的記錄,當(dāng)前指針將位于匹配的記錄上,如果沒有找到記錄,那么將位于下面兩個(gè)位置中的一個(gè):
· 如果是向前搜索,則位于記錄集末尾位置的后面,EOF被設(shè)置為True。
· 如果是向后搜索,則位于記錄集開始位置的前面,BOF被設(shè)置為True。
使用書簽保存位置
如果沒有找到相應(yīng)的記錄,記錄的重新定位可以由書簽輕松解決,因?yàn)榭梢詾楫?dāng)前位置制作書簽,如果在查找記錄過程中沒有找到所需的記錄,那么再移回到上次保存的位置。
例如:
' Save the current position
varBkmk = rsAuthors.Bookmark
' Find the record
rsAuthors.Find "au_lname = 'Sussman'"
' Was it found
If Not rsAuthors.EOF Then
Response.Write "Found: " & rsAuthors ("au_lname") & ", " & _
rsAuthors("au_fname") & "<BR>"
Else
Response.Write "Not found. Moving <BR>"
rsAuthors.Bookmark = varBkmk
End If
使用Filter屬性強(qiáng)于Find方法的一個(gè)原因是Find語句只能一個(gè)查詢條件,而Filter屬性允許指定多個(gè)條件。也就是說,當(dāng)想要查找的字段條件不止一個(gè)時(shí),不能使用Find方法。然而,可以先過濾記錄,如果找到記錄可以再刪除過濾條件。
8.4.6 修改記錄
大部分的Web只用來顯示信息,而Web應(yīng)用程序正變得越來越普遍。在這種情形下,如果只擁有只讀數(shù)據(jù)確實(shí)沒有什么用處。創(chuàng)建一個(gè)應(yīng)用程序,幾乎總是需要修改現(xiàn)存的數(shù)據(jù)或是添加新的數(shù)據(jù),其方法有許多。在本節(jié),將學(xué)習(xí)如何使用Recordset對象的方法來更改數(shù)據(jù)。在下一章,將會(huì)看到如何使用查詢完成相同的任務(wù)。
可以設(shè)置除了adLockReadOnly之處的鎖定類型配合使用Recordset對象的方法去修改數(shù)據(jù)(假定有相應(yīng)的權(quán)限)。記住,缺省的鎖定類型是只讀的。
1. 添加記錄
要在記錄集中添加記錄,使用AddNew方法。有兩種使用AddNew的方法。第一種沒有任何參數(shù),僅僅調(diào)用AddNew,在記錄集的最后添加一個(gè)空記錄。在調(diào)用Update方法保存所做的更改之前,可以隨意地修改字段中的數(shù)據(jù):
With rsAuthors
.Open "authors", strConn, adOpenDynamic, _
adLockOptimistic, adCmdTableDirect
.AddNew
.Fields("au_id") = "123-12-1234"
.Fields("au_lname") = "Lloyd"
.Fields("au_fname") = "Janine"
.Fields("contract") = 0
.Update
End With
這只是添加了一條新記錄,設(shè)置四個(gè)強(qiáng)制型的字段值。
另一種方法是使用AddNew方法的可選參數(shù),這是兩個(gè)數(shù)組,一個(gè)是字段名,另一個(gè)是字段的值。
With rsAuthors
.Open "authors", strConn, adOpenDynamic, _
adLockOptimistic, adCmdTableDirect
.AddNew Array("au_id", "au_lname", "au_fname", "contract"), _
Array("123-12-1234", "Lloyd", "Janine", 0)
End With
這個(gè)方法不需要調(diào)用Update方法。
2. 編輯記錄
編輯記錄與添加記錄的方法相似,不同之處在于不需要調(diào)用AddNew方法:
strSQL = "SELECT * FROM authors" & _
"WHERE au_lname='Lloyd'"
With rsAuthors
.Open strSQL, strConn, adOpenDynamic, _
adLockOptimistic, adCmdText
.Fields("contract") =1
.Update
End With
這僅僅是將當(dāng)前記錄(在這種情況下是第一條記錄,因?yàn)閯倓偞蜷_記錄集)的contract字段的值賦為1。
3. 刪除記錄
刪除記錄需調(diào)用Delete方法。刪除哪一條記錄取決于可選的參數(shù),可以是下面AffectEnum常數(shù)中的一個(gè):
· adAffectCurrent:刪除當(dāng)前記錄,缺省操作。
· adAffectGroup:刪除匹配當(dāng)前過濾條件的所有記錄。
· adAffectAll:刪除記錄集中的全部記錄。
· adAffectAllChapters:刪除所有段(chapter)中的記錄。
最簡單的調(diào)用形式是:
rsAuthors.Delete
這將刪除當(dāng)前記錄。如果有一個(gè)過濾條件,并想刪除所有匹配該條件的記錄,那么僅需加上適當(dāng)?shù)某?shù):
rsAuthors.Delete adAffectGroup
4. 自動(dòng)遞增的字段
當(dāng)添加一條新記錄時(shí),一般會(huì)碰到這樣一個(gè)問題:如何處理那些自動(dòng)遞增的或標(biāo)識(shí)字段(Identity Filed)。這些字段是由服務(wù)器自動(dòng)更新的數(shù)字字段,一般用于為每一行提供一個(gè)唯一的字段值。當(dāng)數(shù)據(jù)庫含有多個(gè)表時(shí),那么這個(gè)唯一的字段經(jīng)常被當(dāng)作關(guān)聯(lián)表的外鍵。所以,添加一條新記錄時(shí),經(jīng)常需要找出它們的值。
例如,考慮一下有兩個(gè)字段的表,一個(gè)自動(dòng)遞增的ID字段(SQL Server中的IDENTITY字段或Access中的AutoNumber字段),一個(gè)字段名為Name的文本字段?,F(xiàn)在考慮一下下面的向表中添加記錄的代碼:
With rsData
.Open "tblTest", adOpenDynamic, adLockOptimistic, adCmdTableDirect
.AddNew
.Fields("Name") = "Janine"
.Update
intID = .Fields("ID")
End With
看上去很平常,但添加記錄后是否能夠取到這個(gè)值依賴于光標(biāo)的類型、鎖定的類型以及ID字段是否被索引。表8-4列出了哪些組合允許獲取新插入的ID字段的值。其他沒有列在表中的組合不能返回ID字段的值。
表8-4 獲取ID字段的值與光標(biāo)、鎖定的類型及ID字段是否被索引的關(guān)系
提供者
對象
索引
光標(biāo)位置
光標(biāo)類型
鎖定類型
ODBC
Access97
是
服務(wù)器
鍵集
悲觀型
樂觀型
Access2000
是
服務(wù)器
鍵集
悲觀型
樂觀型
否
客戶
所有
悲觀型
樂觀型
SQL Server 6.5
是
服務(wù)器
鍵集
悲觀型
樂觀型
SQL Server 7.0
是
服務(wù)器
鍵集
悲觀型
樂觀型
客戶
所有
悲觀型
樂觀型
否
客戶
所有
悲觀型
樂觀型
Jet 4.0
Access97
是
服務(wù)器
所有
所有
Access 2000
是
服務(wù)器
所有
所有
否
客戶
所有
悲觀型
樂觀型
SQL OLE DB
SQL Server 6.5
SQL Server 7.0
是
服務(wù)器
鍵集
悲觀型
樂觀型
客戶
所有
悲觀型
樂觀型
否
客戶
所有
悲觀型
樂觀型
這清楚地說明必須使用正確的組合,才能保證能取得ID字段的正確值。否則,可能會(huì)得到0、空值或NULL,這取決于組合的方式。
在下一章中處理存儲(chǔ)過程時(shí),將見到另一種從SQL Server獲取IDENTITY字段值的方法。
8.5 管理錯(cuò)誤
處理數(shù)據(jù)存儲(chǔ)時(shí),發(fā)生錯(cuò)誤的可能性總是存在的:安全性問題,試圖更新已被其他用戶刪除的記錄,諸如此類的問題很多。不能保證一切都運(yùn)行良好,因此必須構(gòu)建某種形式的錯(cuò)誤控制。
在第7章中,研究了ASP頁面中一般的錯(cuò)誤處理,但現(xiàn)在涉及的是數(shù)據(jù)存儲(chǔ),所以必須考慮使用額外的代碼進(jìn)行錯(cuò)誤處理。先看一下Errors集合,再討論其如何滿足ASP 3.0的錯(cuò)誤處理機(jī)制。