SQL Server事务隔离问题 - 全局变量

时间:2011-09-08 16:29:04

标签: sql-server tsql sql-server-2008

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
  • REPEATABLE READ - 导致死锁
  • READ COMMITTED - 导致重复的密钥插入

@changeTimeStamp是我的参数。 TSMChangeTimeStamp只保留一个值。

如果有人知道如何解决这个问题,我将不胜感激。

2 个答案:

答案 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锁定并更新表中的每条记录(如果适用的话)。