asp记录集RecordCount游标 | 熊阿哥博客

asp记录集RecordCount游标

ASP   2025-02-27 13:48   58   0  

一、现象:ADO的RECORDSET的RECORDCOUNT属性总是为-1

当在服务器端请求RecordCoun时会返回-1。这是因为ActiveX Data Objects (ADO) 2.0中的CursorType是adOpenForwardonly或者adOpenDynamic。如果是ADO 1.5,只发生在cursortype是adOpenForwardonly的时候。如果使用OLEDB provider for JET和SQL Server产生的结果可能不同,这依赖于数据库的提供者。

提供者可能不支持某些CursorTypes。当你选择的CursorType不被支持时,提供者将选择最接近于你所请求的CursorType。请参考你的提供者的文档。此外,请注意不是所有的LockType和CursorType的组合都可以同时工作。改变LockType将强制改变CursorType。请确定使用调试来检查CursorType的值。


二、原因:Forward only的游标无法返回RecordCount

在动态的游标中纪录号可能改变。Forward only的游标无法返回RecordCount。

这个形式是设计决定的。

set rs = Server.CreateObject("ADODB.Recordset")

rs.open sql,conn,打开方式,锁类型

参数一表示游标类型,如下设置:

参数1 意 义

0 只读, 数据只能向下移动

1 可读写,数据可以自由移动,多用户下别人不能看到新增数据(除非重启动)

2 可读写,数据可以自由移动,多用户下别人可以看到新增数据

3 只读 , 数据可以自由移动

参数2表示锁定类型,如下:

参数2 意 义

1 默认值, 只读

2 悲观锁定

3 乐观锁定

4 批次乐观锁定

也就是说第一个参数为1或2的时候,才能有recordcount

所以也可以用recordset.open打开数据源:

rs.CursorLocation = adUseClient

rs.CursorType = adOpenStatic

rs.open sqlstring,conn

在我的程序中,改为第二种打开方式就可以正确访问RecordSet的那些属性了.具体就是:

rs.Open sqlstring,conn,1,3

那么CursorLocation和CursorType到底是什么东西,能产生这么大的影响?

(1)CursorLocation:

设置或返回游标引擎的位置, 可设置为以下某个常量的长整型值:

adUseNone: 没有使用游标服务.(该常量已过时并且只为了向后兼容才出现)

adUseClient:

使用由本地游标库提供的客户端游标。本地游标引擎通常允许使用的许多功能可能是驱动程序提供的游标无法使用的,因此使用该设置对于那些将要启用的功能是有好处的。adUseClientBatch 与 adUseClient 同义,也支持向后兼容性。

到这里大家应该明白为什么我们的游标会出问题及解决办法了.

adUseServer:

默认值。使用数据提供者或驱动程序提供的游标。这些游标有时非常灵活,对于其他用户对数据源所作的更改具有额外的敏感性。但是,Microsoft Client Cursor Provider(如已断开关联的记录集)的某些功能无法由服务器端游标模拟,通过该设置将无法使用这些功能。

注:当用于客户端(ADOR)RecordSet或Connection对象时,只能将CursorLocation属性设置为adUseClient.

(2)CursorType:

指示在RecordSet对象中使用的游标类型,设置或返回以下某个CursorTypeEnum值:

adOpenForwardOnly(=0):

仅向前游标,默认值.与静态游标相同,但只能在记录中向前滚动.当需要在记录集中单向移动时,可用于提高性能.

adOpenKeyset(=1):

键集游标。尽管从您的记录集不能访问其他用户删除的记录,但除无法查看其他用户添加的记录外,键集游标与动态游标相似。仍然可以看见其他用户更改的数据。

adOpenDynamic(=2):

动态游标。可以看见其他用户所作的添加、更改和删除。允许在记录集中进行所有类型的移动,但不包括提供者不支持的书签操作。

adOpenStatic(=3):

静态游标。可以用来查找数据或生成报告的记录集合的静态副本。另外,对其他用户所作的添加、更改或删除不可见。

注:如果将 CursorLocation 属性设置为 adUseClient,则只支持 adOpenStatic 的设置。如果设置了不支持的值,不会导致错误,并将使用最接近支持的 CursorType。

当用于客户端 (ADOR) Recordset 对象时,只能将 CursorType 属性设置为 adOpenStatic。

以上部分内容 摘自:CSDN博主「boabc2304」的文章,原文链接


三、解决办法:使用adOpenKeyset(=1)或者adOpenStatic(=3)

使用adOpenKeyset(=1)或者adOpenStatic(=3)作为服务器端游标或者客户端游标。客户端只使用adOpenStatic作为CursorTypes,而不管你选择什么样的CursorType。

四、ADO如何提高速度和效率

如果只读则尽量使用adOpenForwardOnly参数。 再搭配 adCmdText 或adCmdTable 速度会快很多

如果表字段很多,Select 语句尽量只取需要的字段,而不是全部用*

有些Ole字段 或 长文本 二进制字段占用空间比较大,如非必要,尽量避免每次都读取它

适当使用索引和筛选条件


五、网上其它相关资料:

rs.CursorLocation= adUseClient '设为adUseClient

rs.Open"sql语句",conn '或者游标类型为adOpenStatic

将返回记录总数

当CursorType=1时,rs.RecordCount是不可用的,将其设为3即可。

你只要将RecordSet的游标类型设置为客户端游标类型就行了:

设置cursorlocation=adUseServer

打开参数只有在为adopenstastic的情况下recordcont属性才能正确显示数据集中的记录值Recordset对象的游标类型会影响是否能够确定记录的数目。对仅向前游标,RecordCount性将返回-1,对静态或键集游标返回实际计数,对动态游标取决于数据源,返回-1或实际计数。

RS.OPEN SQL,CONN,A,B A为游标类型,B为锁类型

A: adOpenForwardOnly(=0) 只读,且当前数据记录只能向下移动

adOpenKeySet(=1) 只读,当前数据记录可自由移动

adOpenDynamic(=2) 可读写,当前数据记录可自由移动

adOpenStatic(=3) 可读写,当前数据记录可自由移动,可看到新增记录

B: adLockReadOnly(=1) 缺省锁定类型,记录集是只读的,不能修改记录

adLockPessimistic(=2) 悲观锁定,当修改记录时,数据提供者将尝试锁定记录以确保成功地编辑记录。只要编辑一开始,则立即锁住记录。

adLockOptimistic(=3) 乐观锁定,直到用Update方法提交更新记录时才锁定记录。

adLockBatchOptimistic(=4) 批量乐观锁定,允许修改多个记录,只有调用UpdateBatch方法后才锁定记录。 当不需要改动任何记录时,应该使用只读的记录集,这样提供者不用做任何检测。对于一般的使用,乐观的锁定可能是最好的选择,因为记录只被锁定一小段时间,数据在这段时间被更新。这减少了资源的使用。


引用:


记录集是否可写不是由光标类型决定的,而是由锁类型决定的。第一种光标(adOpenForwardOpnly)只能向前移动,第二种光标(adOpenStatic)可自由移动。但它们只决定了记录集是静态的,而不是“只读”的。而后面两种也不是“可读写”的,而是“动态”的。


记录集分动态、静态两种,区别在于,记录集在打开的过程中,是否实时反映用户对数据库的更改(可能是当前访问数据集的用户,也可能是其他用户)。


adOpenForwardOnly和adOpenStatic这两种属静态类型,当前用户打开记录集后,记录集就保持不变一直到关闭后再次打开它。在这过程中如果数据库中的相应记录发生改变,在当前用户是看不到的。


adOpenDynamic和adOpenKeyset这两种则属动态类型,记录集会反映出数据库中相应记录的更改,他们两者的区别在于:adOpenDynamic是完全动态的,数据库记录的更新、删除、添加都会体现在当前用户所打开的记录集中;而adOpenKeyset则保持当前记录集的个数不变,它只体现更新操作,不体现删除和添加操作。


另外,建议大家使用相应的ADO常量,而不是用一些让人摸不着头脑的数字。ADO常量非常有用,建议大家去记这些常量,而不是记数字。常量由英文单词组成,可以提高代码的可读性,更重要的是帮助我们理解常量所充当的作用。


通常用于单纯显示的记录集,只需要用只向前、只读类型即可,而这两个属性是默认的,所以可以不设置,如:RS.Open strSQL, conn, adOpenForwardOnly, adLockReadOnly 等同于 RS.Open strSQL, Conn 打开这种记录集的执行效率是最高的!例外的是需要对记录集进行分页,这时必须替换adOpenForwardOnly为其它的,比如adOpenStatic就不错。而通常大家使用的rs.Open sql, cn, 1, 1则需要更多的时间来打开,而应用中通常并不需要。


Recordset对象所有的属性和方法


Recordset 属性 adOpenForwardOnly adOpenKeysetadOpenDynamic adOpenStatic


AbsolutePage 不支持 不支持 可读写 可读写


AbsolutePosition 不支持 不支持 可读写 可读写


ActiveConnection 可读写 可读写 可读写 可读写


BOF 只读 只读 只读 只读


Bookmark 不支持 不支持 可读写 可读写


CacheSize 可读写 可读写 可读写 可读写


CursorLocation 可读写 可读写 可读写 可读写


CursorType 可读写 可读写 可读写 可读写


EditMode 只读 只读只读 只读


EOF 只读 只读 只读 只读


Filter 可读写 可读写可读写 可读写


LockType 可读写 可读写 可读写 可读写


MarshalOptions 可读写 可读写 可读写 可读写


MaxRecords 可读写 可读写 可读写 可读写


PageCount 不支持 不支持 只读 只读


PageSize 可读写 可读写 可读写 可读写


RecordCount 不支持 不支持 只读 只读


Source 可读写 可读写可读写 可读写


State 只读只读 只读 只读


Status 只读 只读只读 只读


AddNew 支持 支持支持 支持


CancelBatch 支持 支持 支持 支持


CancelUpdate 支持 支持 支持 支持


CancelUpdate 支持 支持 支持 支持


Close 支持支持 支持 支持


Delete 支持 支持支持 支持


GetRows 支持 支持 支持 支持


Move 不支持支持 支持 支持


MoveFirst 支持 支持 支持 支持


MoveLast 不支持 支持 支持 支持


MoveNext 支持 支持 支持 支持


MovePrevious 不支持 支持 支持 支持


NextRecordset 支持 支持 支持 支持


Open 支持支持 支持 支持


Requery 支持 支持 支持 支持


Resync 不支持 不支持支持 支持


Supports 支持 支持 支持 支持


Update 支持 支持支持 支持


UpdateBatch 支持 支持 支持 支持




综上所述,我们可以考虑以下几条意见:


意见1:


在打开recordset记录集的时候,如果参数3(就是CursorType)为键盘索引或者向前索引时(CursorType参数为0or 1),为了提高处理速度,recordset纪录是一条一条给你的,而不是一下子都给你的。解决方法是使用动态或静态索引(CursorType参数为2 or 3)


意见2:


因为在c/s结构中,记录集是分页存储的,当你从服务器请求数据时,它不会给你全部数据。最好用rs.getrows()的到所有记录行


意见3:


将ADO连接的CursorLocation属性设置为客户端:rs.CursorLocation = adUseClient就行了。


意见4:


如果只是要判断ADO的RECORDSET为空,用RECORDSET.EOF=TRUE就行了!我从不用RECORDSETCOUNT=0判断是否为空!


意见5:


如果ADO的RECORDCOUNT为-1,只要设置CursorType参数为2 or 3就行啊。


六、国外与此相关的文章

使用 VBA 获取 Recordset 对象中正确的记录数


您的 Recordset 是否为其 RecordCount 属性返回 -1?如果是,本文将能够帮助您并解释原因和解决方法。


如果您在 VBA 项目中使用过Microsoft ADO ,则必须使用 Recordset 对象。Recordset 只是内存中的一个临时表,其中包含数据的行和列。您可以浏览记录集并执行您合法执行的任何处理。


Recordset 对象有一个RecordCount 属性 ,该属性指示 Recordset 中有多少条记录。当我在 1999 年第一次使用 ADO 时,我困惑了一年多,为什么 RecordCount 总是返回 -1。经过多次测试和深入研究帮助文档,我意识到罪魁祸首是我用于记录集的游标类型。


默认情况下,ADO 为记录集隐式创建只进游标,并在使用下列方法之一时在 RecordCount 属性中返回 -1。


如果未指定游标类型,则使用 Recordset 对象的 Open 方法打开记录集对象时。

使用 Connection 对象的 Execute 方法获取 Recordset 对象时。这个方法没有给我们指定游标类型的选项。

下面的前两个代码示例演示了如何使用仅向前游标创建记录集。然后再给出两个例子来说明如何创建返回有效记录计数的记录集。


要使此页面上的代码正常工作,您需要在 Northwind 数据库中添加对 Microsoft ActiveX 数据对象库(从 2.0 到 2.8 的任何版本)的引用。


在 VBA 编辑器中,单击工具 -> 参考...







如何创建在 RecordCount 属性上返回 -1 的 Recordset


以下两个代码片段隐式创建只向前游标,并将在 RecordCount 属性上返回 -1。


要查看以下代码的工作原理,请在Access Northwind 数据库中创建一个包含两个按钮的表单,并将它们命名为 cmdCnnExecute 和 cmdRstOpen。将代码复制到其相关的 On Click 事件过程中。


(1)使用Connection对象的Execute方法——RecordCount返回-1。


Execute 方法返回一个只向前游标类型的记录集。


Private Sub cmdCnnExecute_Click()

    On Error Goto Catch


    Dim strSql As String

    Dim objCnn As ADODB.Connection

    Dim objRst As ADODB.Recordset

    

    '' Get all categories

    strSql = "select CategoryID, CategoryName from Categories"

    

    Set objCnn = CurrentProject.Connection

    Set objRst = New ADODB.Recordset

    

    '' This implicitly creates a recordset object with forward only cursor by default.

    Set objRst = objCnn.Execute(strSql)


    '' Display the number of records in Immediate window. Returns -1    

    Debug.Print "objRst (adOpenForwardOnly) record count: " & objRst.RecordCount

                

    '' Clean up

    Set objCnn = Nothing    

    objRst.Close

    Set objRst = Nothing

        

    Exit Sub

    

Catch:

    MsgBox "cmdRecordCount_Click(): " & vbCrLf & vbCrLf _

            & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description

End Sub

(2) 使用具有默认游标类型的 Recordset 对象的Open 方法- RecordCount 返回 -1。


在此示例中,Open 方法创建一个只进游标类型的记录集。这是因为在方法中省略了游标类型参数,所以使用了默认参数 adOpenForwardOnly。


Private Sub cmdRstOpen_Click()

    On Error Goto Catch


    Dim strSql As String

    Dim objRst As ADODB.Recordset

    

    '' Get all categories

    strSql = "select CategoryID, CategoryName from Categories"

        

    Set objRst = New ADODB.Recordset

    

    '' This creates a recordset object with forward only cursor by default because

    '' we didn't specify the cursor type enum.

    objRst.Open strSql, CurrentProject.Connection

            

    '' Display the number of records in Immediate window. 

    '' Returns -1

    Debug.Print "objRst (adOpenForwardOnly) record count: " & objRst.RecordCount


    '' Clean up

    objRst.Close

    Set objRst = Nothing

        

    Exit Sub

    

Catch:

    MsgBox "cmdRecordCount_Click(): " & vbCrLf & vbCrLf _

           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description

End Sub

获得有效计数的方法


现在我们将看看如何使用 RecordCount 属性来获得正确的计数。


(1) 客户端游标


当记录集的光标位置被指定为客户端时,它总是返回 RecordCount 属性的有效计数。


客户端游标在 VBA 中指定如下。


objRst.CursorLocation = adUseClient


当记录集是客户端时,在从数据库服务器(例如 Oracle、MySQL 数据库服务器等)检索后,它会被发送到客户端层(例如,您的工作站 PC 用于 MS Access 应用程序,或 Web 服务器用于互联网应用程序)并与数据库服务器断开连接,因此它本质上是静态的。检索后数据库中的任何更改都不会影响记录集中的数据。


请注意,对于本地 Access 数据库,服务器和客户端在同一台机器上,因为服务器是您的 Access Jet 引擎,客户端是您的 VBA 引擎。


(2) 服务器端静态或键集游标。


打开记录集时,默认情况下它作为服务器端的仅向前游标打开。如果我们将其游标类型更改为静态游标或键集游标,它将返回 RecordCount 属性的有效计数。


下面的代码打开一个静态游标。


objRst.CursorType = adOpenStatic '' 或者直接在 Open 方法中指定 adOpenStatic。 objRst.Open strSql,CurrentProject.Connection,adOpenStatic


下面的代码打开一个键集游标。


objRst.CursorType = adOpenKeyset '' 或者直接在Open方法中指定adOpenKeyset。 objRst.Open strSql,CurrentProject.Connection,adOpenKeyset


要了解有关客户端和服务器端光标的优缺点的更多信息,请参阅 Microsoft 文章 Client-Side Cursors Versus Server-Side Cursors。


返回实际计数的客户端游标示例


下面的代码显示了客户端游标如何返回实际记录数。在 Northwind 数据库中,在您用于测试的表单上,创建一个名为 cmdRecordCountClientSide 的新按钮,然后在其 On Click 事件中复制以下代码。


Private Sub cmdRecordCountClientSide_Click()

    On Error Goto Catch


    Dim strSql As String

    Dim objRst As ADODB.Recordset

    

    '' Get all categories from local Northwind database.

    strSql = "select CategoryID, CategoryName from Categories"

    

    Set objRst = New ADODB.Recordset


    '' Client-side cursor

    objRst.CursorLocation = adUseClient

    

    objRst.Open strSql, CurrentProject.Connection

    

    '' Returns the actual count (8 records)

    Debug.Print "Client-side objRst record count: " & objRst.RecordCount


    '' Clean up

    objRst.Close

    Set objRst = Nothing

        

    Exit Sub

    

Catch:

    MsgBox "cmdRecordCount_Click()" & vbCrLf & vbCrLf _

           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description

End Sub

即时窗口显示客户端游标的实际计数。





所有四种服务器端游标类型的示例


下面的代码显示了具有四种不同游标类型的四个记录集。静态和键集游标返回实际计数。仅向前和动态游标返回 -1。因为我们没有指定光标位置,所以它默认为服务器端。另一方面,由于记录是从本地 Access Northwind 数据库中检索的,因此客户端和服务器端都在本地计算机上。


在 Northwind 数据库中,在您用于测试的表单上,创建一个名为 cmdRecordCount 的新按钮,然后在其 On Click 事件中复制以下代码。




Private Sub cmdRecordCount_Click()

    On Error Goto Catch


    Dim strSql As String

    Dim objRst1 As ADODB.Recordset

    Dim objRst2 As ADODB.Recordset

    Dim objRst3 As ADODB.Recordset

    Dim objRst4 As ADODB.Recordset


    '' Get all categories from local Northwind database.

    strSql = "select CategoryID, CategoryName from Categories"

    

    '' In code below, because we didn't specify cursor location, it's server-side by default.

    

    '' Returns -1

    Set objRst1 = New ADODB.Recordset

    objRst1.Open strSql, CurrentProject.Connection, adOpenForwardOnly


    '' Returns -1

    Set objRst2 = New ADODB.Recordset

    objRst2.Open strSql, CurrentProject.Connection, adOpenDynamic


    '' Returns valid count

    Set objRst3 = New ADODB.Recordset

    objRst3.Open strSql, CurrentProject.Connection, adOpenKeyset


    '' Returns valid count

    Set objRst4 = New ADODB.Recordset

    objRst4.Open strSql, CurrentProject.Connection, adOpenStatic

        

    '' Display the number of records in Immediate window.

    Debug.Print "objRst1 (adOpenForwardOnly) record count: " & objRst1.RecordCount

    Debug.Print "objRst2 (adOpenDynamic) record count: " & objRst2.RecordCount

    Debug.Print "objRst3 (adOpenKeyset) record count: " & objRst3.RecordCount

    Debug.Print "objRst4 (adOpenStatic) record count: " & objRst4.RecordCount


    '' Clean up

    objRst1.Close

    objRst2.Close

    objRst3.Close

    objRst4.Close

    Set objRst1 = Nothing

    Set objRst2 = Nothing

    Set objRst3 = Nothing

    Set objRst4 = Nothing

        

    Exit Sub

    

Catch:

    MsgBox "cmdRecordCount_Click()" & vbCrLf & vbCrLf _

           & "Error#:  " & Err.Number & vbCrLf & vbCrLf & Err.Description

End Sub

立即窗口显示四个值。





请注意:


(1) 如果您(在极少数情况下)使用静态游标或键集游标但仍为 -1,则将锁类型指定为 adLockOptimistic 可能会解决您的问题。


(2) 如果指定了动态游标,我们可能会根据情况得到 -1 或实际计数,但仅向前游标总是返回 -1。



博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。