关系数据库中的操作会对整个行集起作用。由 SELECT 语句返回的行集包括满足该语句的 WHERE 子句中条件的所有行。这种由语句返回的完整行集称为结果集。应用程序并不总能将整个结果集作为一个单元来有效地处理。这些应用程序需要一种机制以便每次处理一行或一部分行。游标不仅可提供这种机制,而且是对结果集的一种扩展。
游标通过执行以下操作来扩展结果集处理:
允许定位在结果集的特定行。
从结果集的当前位置检索一行或一部分行。
支持对结果集中当前位置的行进行数据修改。
为由其他用户对显示在结果集中的数据库数据所做的更改提供不同级别的可见性支持。
注意: |
---|
有关 SQL Server 游标类型的完整说明,请参阅 SQL Server 联机丛书中的“游标类型(数据库引擎)”主题。 |
JDBC 规范支持的只进和可滚动游标对其他作业所做的更改可能敏感,也可能不敏感,而且可以是只读游标或可更新游标。这一功能由 Microsoft SQL Server 2005 JDBC Driver 的 SQLServerResultSet 类提供。
JDBC 驱动程序支持以下游标类型:
结果集 (游标)类型 | SQL Server 游标类型 | 特征 | 选择 方法 | 响应 缓冲 | 说明 |
---|---|---|---|---|---|
TYPE_FORWARD_ONLY (CONCUR_READ_ONLY) |
不适用 |
只进,只读 |
direct |
full |
应用程序必须在结果集中进行一次(前进)传递。这是默认行为,其方式与 TYPE_SS_DIRECT_FORWARD_ONLY 游标的方式相同。在语句执行期间,驱动程序将整个结果集从服务器读入内存中。 |
TYPE_FORWARD_ONLY (CONCUR_READ_ONLY) |
不适用 |
只进,只读 |
direct |
adaptive |
应用程序必须在结果集中进行一次(前进)传递。其行为与 TYPE_SS_DIRECT_FORWARD_ONLY 游标的行为相同。当应用程序请求行时,驱动程序从服务器读取对应的行,这样可以最大限度地减少客户端内存占用。 |
TYPE_FORWARD_ONLY (CONCUR_READ_ONLY) |
快进 |
只进,只读 |
cursor |
full 或 adaptive |
应用程序必须通过使用服务器游标在结果集中进行一次(前进)传递。其行为与 TYPE_SS_SERVER_CURSOR_FORWARD_ONLY 游标的行为相同。 |
TYPE_FORWARD_ONLY (CONCUR_UPDATABLE) |
动态(只进) |
只进,可更新 |
direct 或 cursor |
full 或 adaptive |
应用程序必须在结果集中进行一次(前进)传递才能更新一行或多行。 默认情况下,当应用程序调用 SQLServerResultSet 对象的 setFetchSize 方法时,提取大小是固定的。 对于这种情况,为了获得自适应缓冲,应用程序必须通过提供一个 String 值“adaptive”,以调用 SQLServerStatement 对象的 setResponseBuffering 方法。 |
TYPE_SCROLL_INSENSITIVE |
静态 |
可滚动,不可更新 |
direct 或 cursor |
full 或 adaptive |
应用程序需要数据库快照。 |
TYPE_SCROLL_SENSITIVE |
键集 |
可滚动且可更新。行更新是可见的,删除显示为缺失数据。从结果集中插入是可见的,但从结果集之外插入是不可见的。 |
direct 或 cursor |
full 或 adaptive |
应用程序必须只看到现有行的已更改数据。 |
TYPE_SS_DIRECT_FORWARD_ONLY |
不适用 |
只进,只读 |
direct 或 cursor |
full 或 adaptive |
整数值 = 2003。提供一个完全缓冲的只读客户端游标。不创建服务器游标。 |
TYPE_SS_SERVER_CURSOR_FORWARD_ONLY |
快进 |
只进 |
direct 或 cursor |
full 或 adaptive |
整数值 = 2004。快速,访问所有数据。 |
TYPE_SS_SCROLL_STATIC |
静态 |
不反映其他用户的更新 |
direct 或 cursor |
full 或 adaptive |
整数值 = 1004。应用程序需要数据库快照。这是 JDBC TYPE_SCROLL_INSENSITIVE 特定于 SQL Server 的同义词。 |
TYPE_SS_SCROLL_KEYSET |
键集 |
反映其他用户的更新;行成员身份是固定的 |
direct 或 cursor |
full 或 adaptive |
整数值 = 1005。应用程序必须只看到现有行的已更改数据。这是 JDBC TYPE_SCROLL_SENSITIVE 特定于 SQL Server 的同义词。 |
TYPE_SS_SCROLL_DYNAMIC |
动态 |
可滚动且可更新。行更新是可见的,而删除显示为当前提取缓冲区中临时缺失数据。从结果集内插入和从结果集之外插入都是可见的。 |
direct 或 cursor |
full 或 adaptive |
整数值 = 1006。应用程序在游标的生存期内必须看到现有行的已更改数据并看到已插入和已删除的行。 |
游标定位
TYPE_FORWARD_ONLY、TYPE_SS_DIRECT_FORWARD_ONLY 和 TYPE_SS_SERVER_CURSOR_FORWARD_ONLY 游标仅支持 next 定位方法。
TYPE_SS_SCROLL_DYNAMIC 游标不支持 absolute 和 getRow 方法。absolute 方法近似等效于针对动态游标组合调用 first 和 relative 方法。
getRow 方法仅受 TYPE_FORWARD_ONLY、TYPE_SS_DIRECT_FORWARD_ONLY、TYPE_SS_SERVER_CURSOR_FORWARD_ONLY、TYPE_SS_SCROLL_KEYSET 和 TYPE_SS_SCROLL_STATIC 游标支持。带有所有只进游标类型的 getRow 方法返回迄今为止通过游标读取的行数。
注意: |
---|
当应用程序进行不支持的游标定位调用或对 getRow 方法进行不支持的调用时,将引发异常并显示消息“此游标类型不支持所请求的操作”。 |
仅 TYPE_SS_SCROLL_KEYSET 和等效的 TYPE_SCROLL_SENSITIVE 游标才显示已删除的行。如果游标定位在已删除的行上,则列值不可用并且 rowDeleted 方法返回“true”。对 get<Type> 方法的调用将引发异常并显示消息“无法从删除的行获得值”。无法更新已删除的行。如果您尝试对已删除的行调用 update<Type> 方法,将引发异常并显示消息“无法更新已删除的行”。TYPE_SS_SCROLL_DYNAMIC 游标具有这种相同的行为,直到将此游标移出当前提取缓冲区之外。
前进游标和动态游标以类似的方式显示已删除的行,但仅限仍可在提取缓冲区中访问游标的情况。对于前进游标,这一点相当简单。但对于动态游标,当提取大小大于 1 时,这一点就变得较复杂了。应用程序可能在由提取缓冲区定义的窗口内前后移动游标,但是,当离开在其中更新已删除行的原始提取缓冲区时,已删除的行将消失。如果应用程序并不希望通过使用动态游标来查看临时删除的行,则应使用 Fetch Relative (0)。
如果使用游标更新 TYPE_SS_SCROLL_KEYSET 或 TYPE_SCROLL_SENSITIVE 游标行的键值,则行将保持其在结果集中的原始位置,无论已更新的行是否符合游标的选择条件。如果在游标之外更新行,则已删除的行将出现在该行的原始位置,然而,该行仅当游标中存在具有新键值的另一行但它先前已被删除时才会出现在游标中。
对于动态游标,已更新的行将保留其在提取缓冲区的位置,直到离开由提取缓冲区定义的窗口。已更新的行随后可能重新出现在结果集内的不同位置,或者可能完全消失。必须避免结果集中出现临时不一致的应用程序所使用的提取大小应为 1(对于 CONCUR_SS_SCROLL_LOCKS 并发机制,默认值为 8 行;对于其他并发机制,则为 128 行)。
游标转换
SQL Server 有时选择实现的游标类型与所请求的游标类型不同,这称为隐式游标转换(或游标降级)。有关隐式游标转换的详细信息,请参阅 SQL Server 联机丛书中的“使用隐式游标转换”主题。
对于 SQL Server 2000,当您通过 ResultSet.TYPE_SCROLL_SENSITIVE 和 ResultSet.CONCUR_UPDATABLE 结果集更新数据时,将引发异常并显示消息“游标为只读”。发生此异常的原因是 SQL Server 2000 已针对该结果集执行了隐式游标转换,而不返回所请求的可更新游标。
若要解决此问题,可以采用以下两种解决方案之一:
确认基础表具有主键
创建语句时,使用 SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC,而不使用 ResultSet.TYPE_SCROLL_SENSITIVE。
游标更新
对于游标而言,如果游标类型和并发支持更新,则支持对游标进行就地更新。如果游标未定位在结果集中的可更新行上(get<Type> 方法调用未获成功),则调用 update<Type> 方法将引发异常并显示消息“结果集没有当前行”。JDBC 规范规定,当对游标的列 CONCUR_READ_ONLY 调用 update 方法时,将引发异常。在由于乐观并发冲突(如相互竞争更新或删除)等此类原因而导致无法更新行的情况下,可能不会引发异常,直到调用 insertRow、updateRow 或 deleteRow。
在调用 update<Type> 之后,get<Type> 将无法访问受影响的列,直到调用了 updateRow 或 cancelRowUpdates。这可以避免出现相关的问题:使用与服务器返回的类型不同的类型更新列,后续的 getter 调用可能调用客户端类型转换(这种转换会给出不准确的结果)等。调用 get<Type> 将引发异常并显示消息“无法访问已更新的列,直到调用 updateRow() 或 cancelRowUpdates()”。
注意: |
---|
如果在未更新任何列时调用 updateRow 方法,JDBC 驱动程序将引发异常并显示消息“在未更新任何列时调用了 updateRow()”。 |
在调用了 moveToInsertRow 之后,如果对结果集调用了除 get<Type>、update<Type>、insertRow, 和游标定位方法(包括 moveToCurrentRow)之外的任何其他方法,则将引发异常。moveToInsertRow 方法有效地将结果集置于插入模式,而游标定位方法会终止插入模式。相对游标定位调用会将游标相对于它在调用 moveToInsertRow 之前所处的位置进行移动。在游标定位调用之后,最终的目标游标位置将成为新的游标位置。
如果在插入模式下进行的游标定位调用未获成功,则调用失败之后的游标位置为调用 moveToInsetRow 之前的原始游标位置。如果 insertRow 失败,游标将保持在插入行,并且游标保持在插入模式下。
位于插入行中的列最初处于未初始化状态。调用 update<Type> 方法可将列状态设置为已初始化。对于未初始化的列调用 get<Type> 方法将引发异常。调用 insertRow 方法会将位于插入行中的所有列返回到未初始化状态。
如果在调用 insertRow 方法时任何列均未初始化,则将插入列的默认值。如果没有默认值而列可为空值,则插入 NULL。如果没有默认值且列不可为空值,服务器将返回错误,此时将引发异常。
注意: |
---|
在插入模式下,调用 getRow 方法将返回 0。 JDBC 驱动程序不支持定位更新或删除。根据 JDBC 规范,调用 setCursorName 方法将不起任何作用,而调用 getCursorName 方法将引发异常。 只读和静态游标始终无法更新。 SQL Server 将服务器游标限制为单一结果集。如果批处理或存储过程包含多条语句,则必须使用只进只读客户端游标。 |
游标响应缓冲
对于在上表中指示其 SQL Server 游标类型的任何结果集,在缓冲区中最大可存储由 SQLServerResultSet 对象的 setFetchSize 方法指定的行数。在此类情况下,Microsoft SQL Server 2005 JDBC Driver 版本 1.2 将忽略 responseBuffering 设置的值,但应用程序覆盖 responseBuffering 设置(如在 TYPE_FORWARD_ONLY (CONCUR_UPDATABLE) 事例中指定)的情况除外。在这类情况下,应用程序可以通过使用 String 值“adaptive”来调用 SQLServerStatement 对象的 setResponseBuffering 方法,以覆盖 responseBuffering 设置。