SQL Server 2008 R2(数据中心版 - 我认为)
我对数据库有非常具体的要求。
我需要插入标有时间戳[ChangeTimeStamp]
的行。时间戳值作为参数传递。时间戳必须是唯一的。
两个进程可以同时插入值,偶尔会遇到重复键插入。为了避免这种情况,我正在努力:
declare @maxChangeStamp bigint
set transaction isolation level read committed
begin transaction
select @maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp
if (@maxChangeStamp > @changeTimeStamp)
set @maxChangeStamp = @maxChangeStamp + 1
else
set @maxChangeStamp = @changeTimeStamp
update TSMChangeTimeStamp
set MaxChangeTimeStamp = @maxChangeStamp
commit
set @changeTimeStamp = @maxChangeStamp
insert statment
@changeTimeStamp
是我的参数。
TSMChangeTimeStamp
只保留一个值。
如果有人知道如何解决这个问题,我将不胜感激。
答案 0 :(得分:3)
你没有读取 - 增量 - 更新,无论你尝试什么,这都会失败。总是更新并使用OUTPUT子句来获取新值:
update TSMChangeTimeStamp
set MaxChangeTimeStamp += 1
output inserted.MaxChangeTimeStamp;
如果需要,可以在T-SQL中捕获输出值。但是,虽然这会做你所要求的,但你绝对不想这样做,特别是在一个高端到足以运行DC版本的系统上。生成下一个时间戳将在时间戳资源上放置一个X锁定,从而防止每个其他事务生成新的时间戳,直到当前事务提交为止。您实现了完整的工作序列化,只有一个事务处于活动状态。表演将陷入深渊的底部。
您必须重新审视您的要求并提出更合适的要求。因为现在你的要求也可以表达为“我的系统太快,我怎么能真的真的很慢?”。
答案 1 :(得分:1)
在事务内部,如果模式不是READ COMMITTED或快照隔离,则SELECT语句将获取共享锁。如果两个进程同时启动SELECT,它们将获得共享锁。
稍后,UPDATE语句尝试获取独占锁(或更新锁)。不幸的是,没有人可以获得独占锁,因为另一个进程具有共享锁。
尝试在SELECT语句中使用WITH (UPDLOCK)
table hint。来自MSDN:
UPDLOCK
指定要采取并保持更新锁,直到 交易完成。 UPDLOCK为读取操作获取更新锁 仅限于行级或页面级别。如果UPDLOCK与 TABLOCK或表级锁定是出于其他原因,a 将采用独占(X)锁定。
指定UPDLOCK时,READCOMMITTED和READCOMMITTEDLOCK 隔离级别提示被忽略。例如,如果是隔离级别 会话的设置为SERIALIZABLE,查询指定(UPDLOCK, READCOMMITTED),READCOMMITTED提示被忽略和事务 使用SERIALIZABLE隔离级别运行。
例如:
begin transaction
select @maxChangeStamp = MAX(MaxChangeTimeStamp) from TSMChangeTimeStamp with (updlock)
请注意,如果您的表没有索引(Microsoft KB article 179362),则可以将更新锁提升为表锁。
明确请求XLOCK也可以。
另请注意,您的UPDATE语句没有WHERE子句。这会导致UPDATE锁定并更新表中的每条记录(如果适用的话)。