当前位置:  开发笔记 > 数据库 > 正文

在MS SQL Server中,有没有办法"原子地"递增用作计数器的列?

如何解决《在MSSQLServer中,有没有办法"原子地"递增用作计数器的列?》经验,为你挑选了2个好方法。

假设一个Read Committed Snapshot事务隔离设置,以下语句是"atomic",你不会"失去"并发增量吗?

update mytable set counter = counter + 1

我假设在一般情况下,此更新语句是更大事务的一部分,它不会.例如,我认为这种情况是可能的:

在事务#1中更新计数器

在交易#1中做一些其他的事情

使用事务#2更新计数器

提交事务#2

提交事务#1

在这种情况下,计数器最终只会增加1吗?如果这是交易中唯一的陈述,它会有所作为吗?

像stackoverflow这样的网站如何为其问题视图计数器处理这个问题?或者是否有可能"失去"一些被认为可接受的增量?



1> scott-pascoe..:

根据MSSQL帮助,您可以这样做:

UPDATE tablename SET counterfield = counterfield + 1 OUTPUT INSERTED.counterfield

这将更新一个字段,并将更新的值作为SQL记录集返回.



2> Robert Pauls..:

Read Committed Snapshot仅处理从表中选择数据的锁定.

但是,在t1和t2中,您正在更新数据,这是一种不同的方案.

当您更新计数器时,您会升级到写锁(在行上),从而阻止发生其他更新.t2可以读取,但是t2将在其UPDATE上阻塞,直到t1完成,并且t2将无法在t1之前提交(这与您的时间轴相反).只有其中一个事务将更新计数器,因此两者都会在给出代码时正确更新计数器.(测试)

counter = 0

t1更新计数器(计数器=> 1)

t2更新计数器(已阻止)

t1 commit(counter = 1)

t2 unblocked(现在可以更新计数器)(counter => 2)

t2提交


Read Committed只表示您只能读取已提交的值,但这并不意味着您具有可重复读取.因此,如果您使用并依赖于计数器变量,并打算稍后更新它,那么您可能正在以错误的隔离级别运行事务.

您可以使用可重复的读锁定,或者如果您有时只更新计数器,则可以使用乐观锁定技术自行完成.例如,带有计数器表的时间戳列,或条件更新.

DECLARE @CounterInitialValue INT
DECLARE @NewCounterValue INT
SELECT @CounterInitialValue = SELECT counter FROM MyTable WHERE MyID = 1234

-- do stuff with the counter value

UPDATE MyTable
   SET counter = counter + 1
WHERE
   MyID = 1234
   AND 
   counter = @CounterInitialValue -- prevents the update if counter changed.

-- the value of counter must not change in this scenario.
-- so we rollback if the update affected no rows
IF( @@ROWCOUNT = 0 )
    ROLLBACK

这篇devx文章虽然介绍了它们仍处于测试阶段的功能,但它可以提供信息,因此它可能不完全准确.


更新:正如Justice所指出的,如果t2是t1中的嵌套事务,则语义不同.同样,两者都会正确更新计数器(+2),因为从t1的t1内部来看,计数器已经更新一次.在t1更新它之前,嵌套的t2无法访问计数器.

counter = 0

t1更新计数器(计数器=> 1)

t2更新计数器(嵌套事务)(counter => 2)

t2提交

t1 commit(counter = 2)

对于嵌套事务,如果t1在t1 COMMIT之后发出ROLLBACK,则计数器返回其原始值,因为它还会撤消t2的提交.


在你的第一个例子中,你提到T2可以读取,但会阻止写入(有意义).但是,增量是读取和写入 - 您不希望读取然后写入时阻塞,否则您将读取提交的数据(0),增量(1),然后阻止写入1直到T1写入1.我猜测数据库将阻止读取,因为意图是更新.真的吗?
推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有