Microsoft SQL Server 支持四个用于服务器游标

来源:互联网 发布:淘宝开通网商银行账户 编辑:程序博客网 时间:2024/06/06 11:45

Microsoft SQL Server 支持四个用于服务器游标的并发选项:

  • READ_ONLY

  • OPTIMISTIC WITH VALUES

  • OPTIMISTIC WITH ROW VERSIONING

  • SCROLL LOCKS

READ_ONLY

不允许通过游标进行定位更新,并且不持有针对组成结果集的行的锁。

OPTIMISTIC WITH VALUES

乐观并发控制是事务控制理论的一个标准部分。如果在打开游标与行被更新的间隔内,只有很短的时间可以让另一个用户或进程更新该行,那么这种情况下就可以使用乐观并发控制。当用此选项打开某个游标时,将不持有针对基础行的锁,这有助于最大化吞吐量。如果用户试图修改某一行,则该行中的当前值将与最后一次提取该行时检索到的值进行比较。如果任何一个值发生了更改,服务器就会知道另一个用户或进程已经更新了该行,并返回一个错误。如果所有值都是一样的,服务器就会执行修改。

选择此并发选项将强制使用户或程序员承担责任,以处理那些指明另一个用户已对行进行修改的偶然错误。应用程序收到这种错误时通常采取的措施就是刷新游标,获取新值,然后让用户决定是否对新值进行修改。在 SQL Server 6.5 版或早期版本中,textntextimage 列不用于并发比较。

OPTIMISTIC WITH ROW VERSIONING

此乐观并发控制选项基于行版本控制。使用行版本控制,基础表必须具有某种版本标识符,服务器可用该标识符来确定行被读入游标之后是否有所更改。在 SQL Server 中,此性能由timestamp 数据类型提供,它是一个二进制数字,用于指明数据库中所做的修改的相对顺序。每个数据库都有一个全局当前时间戳值:@@DBTS。每次以任意方式修改带有timestamp 列的行时,SQL Server 都会先将当前的@@DBTS 值存储在 timestamp 列中,然后增加 @@DBTS 值。如果某个表具有timestamp 列,则时间戳会被记到行级。然后,服务器就可以将某一行的当前时间戳值与上次提取该行时存储的时间戳值进行比较,从而确定该行是否已被更新。服务器不必比较所有列中的值,而只需比较timestamp 列即可。如果应用程序对没有timestamp 列的表请求基于行版本控制的乐观并发,则游标将默认为基于数值的乐观并发控制。


为能支持基于行版本的乐观锁,表要建一列类型为timestamp或rowversion,timestamp是rowversion的同义词。详细信息参见下面:

注意:对于通过远程数据源打开的游标,如果远程源不包含 timestamp 列,则不支持通过该游标进行更新。

SCROLL LOCKS

此选项用于实现悲观并发控制,在这种控制中,当把基础数据库行读入游标结果集时,应用程序将尝试锁定这些行。使用服务器游标时,将行读入游标时会在该行上放置一个更新锁。

如果游标是在某个事务内打开的,则该事务更新锁将一直保持到事务被提交或回滚为止;当提取了下一行后,将删除游标锁。(好像有问题?)

如果游标是在事务外打开的,则当提取了下一行后,就会删除锁。

因此,每当用户需要进行完全悲观并发控制时,都应该在事务内打开游标。更新锁将阻止其他任何任务获取更新锁或排他锁,从而阻止其他任何任务更新该行。但更新锁并不阻止共享锁,因此它不会阻止其他任务读取该行,除非第二个任务也在请求带有更新锁的读取。

滚动锁

根据在游标定义中的 SELECT 语句中指定的锁定提示,这些游标并发选项可能会生成滚动锁。在提取每一行时会对其获取滚动锁,并保持到下次提取或者游标关闭为止,以先发生者为准。下次提取时,服务器将为新提取的行获取滚动锁,并释放上次提取的行对应的滚动锁。滚动锁独立于事务锁,并可以保持到提交或回滚操作之后。如果“在提交时关闭游标”的选项为 off,则 COMMIT 语句将不关闭任何打开的游标,而且滚动锁将保持到提交之后,以便维持对所提取数据的隔离。

所获取的滚动锁的类型取决于游标并发选项和游标 SELECT 语句中的锁定提示。

注意:只有由键集驱动的游标和动态游标才支持滚动锁。

锁定提示只读乐观数值乐观行版本控制锁定

无提示

-

-

-

更新

NOLOCK

-

-

-

-

HOLDLOCK

-

-

-

更新

UPDLOCK

-

-

-

更新

TABLOCKX

-

-

-

更新

其他

-

-

-

更新

*指定 NOLOCK 提示将使指定了该提示的表在游标内是只读的。

指定游标并发选项

在每个游标环境下指定的并发选项各不相同:

  • Transact-SQL 游标

    在 DECLARE CURSOR 语句中指定 READ_ONLY、SCROLL_LOCK 和 OPTIMISTIC 关键字。OPTIMISTIC 关键字指定乐观行版本控制,Transact-SQL 游标不支持乐观数值并发选项。

  • ADO 应用程序

    指定 Recordset 对象的 LockType 属性中的 adLockReadOnlyadLockPessimisticadLockOptimisticadLockBatchOptimistic

  • ODBC 应用程序

    将语句特性 SQL_ATTR_CONCURRENCY 设置为 SQL_CONCUR_READ_ONLY、SQL_CONCUR_ROWVER、SQL_CONCUR_VALUES 或 SQL_CONCUR_LOCK。 

timestamp与rowversion区别

公开数据库中自动生成的唯一二进制数字的数据类型。rowversion 通常用作给表行加版本戳的机制。存储大小为 8 个字节。rowversion 数据类型只是递增的数字,不保留日期或时间。若要记录日期或时间,请使用datetime2 数据类型。

注释

每个数据库都有一个计数器,当对数据库中包含 rowversion 列的表执行插入或更新操作时,该计数器值就会增加。此计数器是数据库行版本。这可以跟踪数据库内的相对时间,而不是时钟相关联的实际时间。一个表只能有一个rowversion 列。每次修改或插入包含 rowversion 列的行时,就会在 rowversion 列中插入经过增量的数据库行版本值。这一属性使 rowversion 列不适合作为键使用,尤其是不能作为主键使用。对行的任何更新都会更改行版本值,从而更改键值。如果该列属于主键,那么旧的键值将无效,进而引用该旧值的外键也将不再有效。如果该表在动态游标中引用,则所有更新均会更改游标中行的位置。如果该列属于索引键,则对数据行的所有更新还将导致索引更新。

timestamp 的数据类型为rowversion 数据类型的同义词,并具有数据类型同义词的行为。在 DDL 语句,请尽量使用 rowversion 而不是timestamp。有关详细信息,请参阅数据类型同义词 (Transact-SQL)。

Transact-SQL timestamp 数据类型不同于在 ISO 标准中定义的timestamp 数据类型。

注意:不推荐使用 timestamp 语法。后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。

在 CREATE TABLE 或 ALTER TABLE 语句中,不必为 timestamp 数据类型指定列名,例如:

 复制代码
CREATE TABLE ExampleTable (PriKey int PRIMARY KEY, timestamp);

如果不指定列名,则 SQL Server 数据库引擎 将生成 timestamp 列名;但rowversion 同义词不具有这样的行为。在使用 rowversion 时,必须指定列名,例如:

 复制代码
CREATE TABLE ExampleTable2 (PriKey int PRIMARY KEY, VerCol rowversion) ;
注意:通过使用在其 SELECT 列表中包含了 rowversion 列的 SELECT INTO 语句,可以生成重复的 rowversion 值。建议不要以这种方式使用 rowversion

不可为空的 rowversion 列在语义上等同于 binary(8) 列。可为空的 rowversion 列在语义上等同于 varbinary(8) 列。

使用某一行中的 rowversion 列可以很容易地确定该行中的任何值自上次读取以后是否发生了更改。如果对该行进行了任何更改,就会更新行版本的值。如果没有对行进行更改,则行版本值将与以前读取该行时的行版本值相同。若要返回数据库的当前行版本值,请使用 @@DBTS。

当多个用户正在同时更新行时,可以在表中添加一个 rowversion 列以帮助维护数据库的完整性。此外,您可能还想要在不重新查询表的情况下了解有多少行被更新以及哪些行被更新。


0 0