游标并发(数据库引擎)
MicrosoftSQL Server 支持四个用于服务器游标的并发选项:
READ_ONLY
OPTIMISTIC WITH VALUES
OPTIMISTIC WITH ROW VERSIONING
SCROLL LOCKS
READ_ONLY
不允许通过游标进行定位更新,并且不持有针对组成结果集的行的锁。OPTIMISTIC WITH VALUES
乐观并发控制是事务控制理论的一个标准部分。如果在打开游标与行被更新的间隔内,只有很短的时间可以让另一个用户或进程更新该行,那么这种情况下就可以使用乐观并发控制。当用此选项打开某个游标时,将不持有针对基础行的锁,这有助于最大化吞吐量。如果用户试图修改某一行,则该行中的当前值将与最后一次提取该行时检索到的值进行比较。如果任何一个值发生了更改,服务器就会知道另一个用户或进程已经更新了该行,并返回一个错误。如果所有值都是一样的,服务器就会执行修改。选择此并发选项将强制使用户或程序员承担责任,以处理那些指明另一个用户已对行进行修改的偶然错误。应用程序收到这种错误时通常采取的措施就是刷新游标,获取新值,然后让用户决定是否对新值进行修改。在 SQL Server 6.5 版或早期版本中,text、ntext 和 image 列不用于并发比较。
OPTIMISTIC WITH ROW VERSIONING
此乐观并发控制选项基于行版本控制。使用行版本控制,基础表必须具有某种版本标识符,服务器可用该标识符来确定行被读入游标之后是否有所更改。在 SQL Server 中,此性能由 timestamp 数据类型提供,它是一个二进制数字,用于指明数据库中所做的修改的相对顺序。每个数据库都有一个全局当前时间戳值:**@@**DBTS。每次以任意方式修改带有 timestamp 列的行时,SQL Server 都会先将当前的 **@@**DBTS 值存储在 timestamp 列中,然后增加 **@@**DBTS 值。如果某个表具有 timestamp 列,则时间戳会被记到行级。然后,服务器就可以将某一行的当前时间戳值与上次提取该行时存储的时间戳值进行比较,从而确定该行是否已被更新。服务器不必比较所有列中的值,而只需比较 timestamp 列即可。如果应用程序对没有 timestamp 列的表请求基于行版本控制的乐观并发,则游标将默认为基于数值的乐观并发控制。注意 对于通过远程数据源打开的游标,如果远程源不包含 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 属性中的 adLockReadOnly、adLockPessimistic、adLockOptimistic 或 adLockBatchOptimistic。
ODBC 应用程序
将语句特性 SQL_ATTR_CONCURRENCY 设置为 SQL_CONCUR_READ_ONLY、SQL_CONCUR_ROWVER、SQL_CONCUR_VALUES 或 SQL_CONCUR_LOCK。