游标(cursor)
游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果
每个游标区都有一个名字
用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理
主语言是面向记录的,一组主变量一次只能存放一条记录
仅使用主变量并不能完全满足SQL语句向应用程序输出数据的要求
嵌入式SQL引入了游标的概念,用来协调这两种不同的处理方式
在数据库开发过程中,当你检索的数据只是一条记录时,你所编写的事务语句代码往往使用SELECT INSERT 语句。但是我们常常会遇到这样情况,即从某一结果集中逐一地读取一条记录。那么如何解决这种问题呢?游标为我们提供了一种极为优秀的解决方案。
1.游标和游标的优点
在数据库中,游标是一个十分重要的概念。游标提供了一种对从表中检索出的数据进行操作的灵活手段,就本质而言,游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。游标总是与一条SQL 选择语句相关联因为游标由结果集(可以是零条、一条或由相关的选择语句检索出的多条记录)和结果集中指向特定记录的游标位置组成。当决定对结果集进行处理时,必须声明一个指向该结果集的游标。如果曾经用 C 语言写过对文件进行处理的程序,那么游标就像您打开文件所得到的文件句柄一样,只要文件打开成功,该文件句柄就可代表该文件。对于游标而言,其道理是相同的。可见游标能够实现按与传统程序读取平面文件类似的方式处理来自基础表的结果集,从而把表中数据以平面文件的形式呈现给程序。
我们知道关系数据库管理系统实质是面向集合的,在MS SQL SERVER 中并没有一种描述表中单一记录的表达形式,除非使用where 子句来限制只有一条记录被选中。因此我们必须借助于游标来进行面向单条记录的数据处理。由此可见,游标允许应用程序对查询语句select 返回的行结果集中每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作;它还提供对基于游标位置而对表中数据进行删除或更新的能力;而且,正是游标把作为面向集合的数据库管理系统和面向行的程序设计两者联系起来,使两个数据处理方式能够进行沟通。
2. 游标种类
MS SQL SERVER 支持三种类型的游标:Transact_SQL 游标,API 服务器游标和客户游标。
(1) Transact_SQL 游标
Transact_SQL 游标是由DECLARE CURSOR 语法定义、主要用在Transact_SQL 脚本、存储过程和触发器中。Transact_SQL 游标主要用在服务器上,由从客户端发送给服务器的Transact_SQL 语句或是批处理、存储过程、触发器中的Transact_SQL 进行管理。 Transact_SQL 游标不支持提取数据块或多行数据。
(2) API 游标
API 游标支持在OLE DB, ODBC 以及DB_library 中使用游标函数,主要用在服务器上。每一次客户端应用程序调用API 游标函数,MS SQL SEVER 的OLE DB 提供者、ODBC驱动器或DB_library 的动态链接库(DLL) 都会将这些客户请求传送给服务器以对API游标进行处理。
(3) 客户游标
客户游标主要是当在客户机上缓存结果集时才使用。在客户游标中,有一个缺省的结果集被用来在客户机上缓存整个结果集。客户游标仅支持静态游标而非动态游标。由于服务器游标并不支持所有的Transact-SQL 语句或批处理,所以客户游标常常仅被用作服务器游标的辅助。因为在一般情况下,服务器游标能支持绝大多数的游标操作。由于API 游标和Transact-SQL 游标使用在服务器端,所以被称为服务器游标,也被称为后台游标,而客户端游标被称为前台游标。在本章中我们主要讲述服务器(后台)游标
游标详细说明:
RS.OPEN SQL,CONN,A,B
参数A为设定游标的类型,其取值为:
0 仅向前游标,只能向前浏览记录,不支持分页、Recordset、BookMark
1 键集游标,其他用户对记录说做的修改将反映到记录集中,但其他用户增加或删除记录不会反映到记录集中。支持分页、Recordset、BookMark
2 动态游标功能最强,但耗资源也最多。用户对记录说做的修改,增加或删除记录都将反映到记录集中。支持全功能浏览。
3 静态游标,只是数据的一个快照,用户对记录说做的修改,增加或删除记录都不会反映到记录集中。支持向前或向后移动
参数B为记录集的锁定类型,其取值为:
1 锁定类型,默认的,只读,不能作任何修改
2 当编辑时立即锁定记录,最安全的方式
3 只有在调用Update方法时才锁定记录集,而在此前的其他操作仍可对当前记录进行更改、插入和删除等
4 当编辑时记录不会被锁定,而更改、插入和删除是在批处理方式下完成的
打开数据记录集方法其实不止一种,但是我们用的最多的就是
rs.open sql,1,1的方法,可是后面的数字参数很多人不解其意,下面我们来介绍一下。
其实open方法后面有多个参数
CursorType LockType CommandType
比如 rs.open sql,1,1
也可以写成
rs.cursorType = 1
rs.LockType = 1
rs.open sql
其中CursorType代表从一个表或者一个SQL查询结果返回的记录。
这个参数有四个值分别是:
adOpenForwardOnly 表示只允许在记录集内的记录间往前移动。这个是缺省值。
adOpenKeyset 反映由其它用户所做的对记录的改变或者删除动作,但并不反映由其它用户做作的添加新记录的动作。
adOpenDynamic 反映由其它用户所做的对记录的改变或者删除动作,包括添加的新记录
adOpenStatic 不反映其它用户对记录所做的修改,添加,删除动作。
这四个值VBSCRIPT预定义位
adOpenForwardOnly = 0
adOpenKeyset = 1
adOpenDynamic = 2
adOpenStatic = 3
lockType 表示当打开记录集时,数据提供者用于锁定数据库的类型:
adLockReadOnly 数据不能改变,这是缺省值!
adLockPessimistic 数据提供者在开始编辑数据的时候锁定记录
adLockOptimistic 仅当调用update方法时,数据提供者锁定记录
adLockBatchOptimistic 用于批处理修改
他们的常量值定义分别是:
adLockReadOnly = 1
adLockPessimistic = 2
adLockOptimistic = 3
adLockBatchOptimistic = 4
rs.open sql,conn,1,1 读取记录 select
rs.open sql,conn,1,3 只更新记录最好 update
rs.open sql,conn,2,3 插入和删除最好 insert delete
下面的解释:
1. 什幺是游标?
游标,也有人称为光标。概括的讲,它是基于记录的。
过去,关系型数据库没有象现在这样被广泛的应用。那时候,人们大多使用 dBase 这样的小型数据库软件。这类数据库确切的说应为数据文件管理软件。他们是面向记录的。
不过,这种方式也许更符合人们的习惯。比如,我们在电话本中查找号码,在学生档案中查找档案,最终都要归结于其中的一个号码,一个档案,那就是一条记录。现实生活中,我们在一张表格中寻找某一项时,可能会用手一条一条逐行的扫过,以帮助我们找到所需的那条记录。对应于数据库来说,这就是游标的模型。所以,你可以这样想象:表格是数据库中的表,而我们的手好比是游标。
所以,当你使用类似 .MoveNext,.MoveLast 这样的语句时,觉得再自然不过了。
现在,你明白什幺是游标了吧。游标就是数据的 ' 定位系统 ' 。
这个 ' 定位系统 ' 粗分有两种:服务器游标和客户游标。对应于 ADO 中的 CursorLocation 。举例来说:
Set rs = Server.CreateObject("ADODB.RecordSet")
rs.CursorLocation = adUseServer '缺省,使用服务器游标
.....
rs.CursorLocation = adUseClient '使用客户游标
2. 什幺是服务器游标?
或者称为 API 服务器游标。
假设你要查询有关编程语言的书,写成 SQL 语句就是:SELECT book_id,book_title FROM books WHERE book_catalog = '编程' ORDER BY book_title,同时你指定使用服务器游标。
这条语句发送到服务器,服务器对数据进行检索,将符合查询条件的记录集合放入临时表(对某些游标类型是这样)中。每当你进行 .MoveNext 操作,服务器就会发送一条记录到客户端的缓冲区,然后你才可以使用它。
3. 什幺是 CacheSize ?
继续上面的例子,假设符合查询条件的记录有100个,也就是说,用 .MoveNext 这种方法遍历该结果集需要同服务器交互100次。我们可以通过设置 CacheSize 使客户与服务器的通信变少。上面的例子其实就是 CacheSize=1 的情况,这是缺省值。
假设 CacheSize=4,当 RecordSet 对象打开时,服务器发送4条记录到客户端。前4次的 .MoveNext 操作实际上是在客户缓冲区中得到数据,当第5次 .Movenext 时,服务器才发送下一个4条记录。由此,减少了客户与服务器间的网络通信。
那幺是不是说 CacheSize 越大越好呢?千万不要想当然。万事都有两面性,CacheSize 也一样。客户端请求数据,服务器发送数据,这个过程有点象交通管理。CacheSize 过高,会阻塞交通,甚至引起数据丢失(比如当 Cachesize 大于客户端缓冲区时)。对于不同的应用,所取的值也不同。
另外要指出的是,使用任何形式的游标都不是最有效的访问数据的方法,Cachesize 有的时候并不是瓶颈,尽量将使用游标的程序转换为面向结果集的程序,性能会提高很多。
3. 什幺是客户游标?
既然游标是数据的 ' 定位系统 ',那幺在客户端也可以完成。
客户游标的产生由来已久,当初是为了弥补服务器的不足(有些数据库引擎就不支持游标)。随着服务器游标的出现,客户游标似乎已经过时了,不过还是那句话:万事都有两面性,在 internet 上,与数据库的连接并不是永久的,使用客户游标能使我们获得同使用服务器游标一样的功能。
当 CursorLoction 属性设成 adUseClient 时,微软的游标服务( Cursor Service )创建 RecordSet 对象,用前向 / 只读的游标方式从服务器将所有查询结果检索出来,并且存储在客户缓冲区中。当应用程序通过 ADO 请求数据时,游标服务就从客户缓冲区中检取数据。这种方式在连接远程服务器时非常有用,它会提高应用程序的性能。如果你访问的数据库是 Jet 数据库( Access ),而且在本地,那么用客户游标非但不提高性能,还会使性能下降。这时候,数据将被缓存两次,数据库一次,游标服务一次。
如果考虑应用的功能,客户游标功能是很完善的,它能支持某些数据库不能完成的操作( 视数据库的情况而定 )。
4. 什幺是 DisConnected RecordSet ?
我们使用了客户游标,就可以断开与数据库的连接,释放 Connection 对象。这样的结果集就是 DisConnected RecordSet。举例说明:
Dim c As New ADODB.Connection
Dim r As New ADODB.Recordset
On Error GoTo handler
c.ConnectionString = connectStr
c.CursorLocation = adUseClient
c.Open
Set r.ActiveConnection = c
r.Open SqlText, , adOpenKeyset, adLockBatchOptimistic, -1
Set r.ActiveConnection = Nothing ' This disconnects the recordset.
c.Close
Set c = Nothing
......
......
' Recordset is now in disconnected state; do something with it.
r.Close
Set r = Nothing