记录集分页

80酷酷网    80kuku.com

  分页|记录集


     研究RDS数据控件时,学习了如何用DATAPAGESIZE来限制绑定表中显示的记录行数。虽然这是一个既好又简单的解决方法,但其缺点是把所有数据都取到了客户端。例子中只用到了一个规模较小的数据集,但如果需要用到一个很大的数据集,结果会如何?真的想把所有数据都取到客户端吗?毕竟,用户每次只能看到一屏数据。
    这个问题的解决方法是引入分页的概念,每一次只处理一页数据,并且只返回这一页数据,而不是全部数据。为了实现分页处理数据,需要处理与Recordset对象相关的三个属性,如表1 0 - 7所示。

    可使用AbsolutePage属性将记录指针指向某页面中的第一条记录,这样可以直接在页面间移动。例如:

    如果使用缺省的页面大小1 0,上面的代码行则将记录指针指向记录集的第11条记录。
    需要着重注意的是,页面中的记录不是固定的,记录的数量是固定的,但并不是记录本身。这听起来可能不太好理解,但如果回想一下讨论光标类型的第8章内容,可能会记得某些类型的光标是基于键的。实际的数据并不会被读取到客户端,直到请求这些数据行。这样,如果正在使用分页,而其他用户增加了新的行或删除了现有的记录,那么在页面中的实际记录就可能会改变。
    同样需要记住的是,页面中记录的次序与记录集中的次序是一致的,由产生记录集的命令来定义。记录集中的记录没有记录号,因而无法确定它们在记录集中的位置。
    将分页结合到应用程序有好几种方法,其中的两种使用这些属性,第三种方法使用类似的方法,但只适用于SQL Server。
10.4.1 利用ASP页面分页记录集
    第一个要讨论的方法是在本章前面介绍过的RDS方法的一个扩展。我们将使用RDS数据控件和U R L参数,先有一个返回一组记录的A S P页面,然后这些记录由RDS数据控件使用。如果想引入分页,必须确定这个A S P页面只返回一个充满数据的页面。
    先研究提供数据的A S P页面。为使其更具有灵活性,允许一个包含两条信息的查询字符串传到页面中:

    此时,得到了一个充满数据的记录集,但仅需要一个页面。因此,必须使用A b s o l u t e P a g e属性来设置想要的页面。在设置A b s o l u t e P a g e属性之前,需要检测请求的页码不是0,或不大于总页数。在这两种情况下,将页面设为最后一页,这由P a g e C o u n t属性确定。

    现在,已经位于正确的页上,所以接下来的问题就是如何将这一页传送给客户端。为了实现这一点,只需用一个“转储”记录集把该页中的记录提取出来。创建一个新的,与含有数据的记录集相同结构的记录集,同时将数据拷贝到新的记录集中。
    转储一个记录集比较简单,包括创建一个Recordset对象,设置光标位置为基于客户端。然后将字段添加到F i e l d s集合,使用数据记录集为这些字段提供细节。一旦创建完字段,只需简单地打开记录集,不必指定任何数据源或连接的细节。


    我们用新创建的按钮来控制分页,这些按钮调用setPage方法,其参数确定要移到哪一页。



    尽管如此,这段代码存在着一个主要的问题需要解决,因为客户并不知道有多少页数据。可以很容易地直接请求到最后一页数据,但是当一页页下移时,却不知道什么时候超出最后一页。A S P页面能够知道,但在客户端却不行。这意味着即使A S P页面只显示最后一页,客户端的页号仍然在持续增加。
    使用自定义组件
    解决前面例子中的页码问题的一种方法是使用组件来提供数据,而不是A S P页面。这里不想进行仔细的研究,但这个概念非常类似。首先要清除U R L的细节,然后在r e s e t D a t a函数中使用D a t a S p a c e对象和D a t a F a c t o r y对象来创建一个自定义组件。
    这个组件所含的代码可能与A S P页面的代码非常相似,也返回一个含有数据页的记录集。但由于组件可以不止返回一个记录集,所以实际上可以跟踪页的最大数量,这使分页变得更智能化。
10.4.2 利用ADO分页
    另一个解决页码问题的方法是使用一种著名的分页技术。不采用RDS数据绑定,而是在A S P页面内创建一个H T M L表格。使用相同的分页方法,但并不转储记录集。


    现在,必须设置页码。第一次显示时Q u e r y S t r i n g的值可能为空,因此缺省设为第一页。如果指定了页,那么检测是否超出可接受的页范围。如果小于第一页就设为第一页,如果大于最后一页就设为最后一页。




    这就是ADO分页。一个相当简单的分页程序给出了图1 0 - 1 5所示的结果。
    这里显示的是第一页数据,因此可以看到上一页控件是不可用的。
    这种解决方案给用户提供了一个较好的界面,因为控件以一种很实际的工作方式运转着。然而,仍然存在一个问题,向前翻页的实现使得每次请求页面时就要打开整个记录集。实际上所做的全部工作是把记录集从客户端移到了服务器。现在必须承认带宽方面是改进了,但很多请求的记录超出了我们所需要的。
10.4.3 利用SQL Server完成记录集分页
    最后一种分页方法的实现也使用了相似的技术,但这次是在SQL Sever中处理页面。这种方法是过去创建两层客户/服务器体系时常采用的一种方法,在这里似乎值得重新使用。利用SQL Server的存储过程创建一个临时表,然后在存储过程中只返回所需的记录。在某种意义上,这有点像转储记录集的解决方法,只是这个时候将转储移到SQL Server中。
    需要解决的主要问题是要选出请求的页中的记录。大多数关系数据库并没有记录号的概念,因此想挑出所需的记录比较困难。最简单的解决方法是复制一个表,增加一个唯一的有序的记录号,这样就可以从复制的表中取出所需的记录。在SQL Server中用I D E N T I T Y列很容易做到这一点,但对于基表我们不能依赖I D E N T I T Y列,因为记录可能会被删除,这样在编号中就会留下空缺。然而,可以创建一个临时表,加入I D E N D I T Y列,这样就能确保顺序编号。

    现在,创建与基表结构相同的临时表,但是增加了额外的I D E N T I T Y列。这里,明确地指定单个表,但也能动态地指定,允许表名由存储过程来提供。当然,动态指定表会降低存储过程的执行速度。



    因此,最后就有了一个只返回一页记录的存储过程。现在需要用一些A S P代码来利用它。
    从声明变量开始。

    不需要创建连接对象,因为ADO会创建一个隐含的连接。
    接下来,为存储过程创建参数。第一个是返回值,保存着从存储过程中返回的页面总数;第二个和第三个参数被传入存储过程,分别指出了请求的页码以及页面的大小。


    创建下一页和最后一页控件需要总页数,它是存储过程的返回值,因此关闭记录集,然后从参数中取出相应的值。

    这种分页方法与前面介绍的使用A S P页面分页的方法有些相似,但仍然有一个问题。必须创建一个含有全部基表记录的临时表。如果基表非常大,即使是一个快速的存储过程,执行起来也会很慢。顺便说一下,如果允许用户对一个含有大量记录的记录集进行分页,那么也必须接受性能损失。
10.4.4 数据分页小结
    到目前为止,已经讨论了三种不同的数据分页方法,但哪一种最好取决于设计的约束条件。
    第一种方法使用RDS,为用户提供了响应速度快的页面。因为所有的数据都在本地机器上,不需要向服务器获取更多的数据。然而,由于所有数据必须立即传到客户端机器,页面加载的速度比其他页面要慢。这也是I E解决方案的一个缺陷。另外两种方法能很快地将页面加载到浏览器,但分页则需要额外的时间。然而,这两种方法不需要任何特殊的客户端组件,比如RDS,因为表格是纯粹的H T M L文档。
    后两个方法的差别不易察觉。用Microsoft Web Application Stress工具进行的严格测试表明,转储记录集的方法速度上稍快一点,但是区别很小。但如果安装SQL Server的机器与We b服务器不同,那么这种差别还是很大的。因此,如果使用这两种方法中的一种,建议最好自己实际测试一下。Microsoft Web Application Stress 工具可以从网址http://homer.rte.microsoft.com获得。
    另一个使用SQLServer进行分页的方法是使用SQL Server光标。它类似于ADO中的光标与记录集,允许访问从查询中获得的数据行。一个光标创建并管理SQL Server中的一个行集。使用SQL光标能从行集的一个绝对位置开始检索数据行,因此,理论上可以创建一个只返回一页从绝对位置开始的数据行的存储过程。不幸的是,SQL光标只允许一次访问一行数据,所以页面中的每一行数据都被作为一个单独的记录集返回。在客户端,我们就必须使用NextRecordset方法对服务器执行额外的操作。因此,这种方法虽然看上去似乎不错,但实际上与这里介绍的使用存储过程的方法相比效率是比较低的。


分享到
  • 微信分享
  • 新浪微博
  • QQ好友
  • QQ空间
点击: