有人在SQL Server 2008中编写了以下存储过程。我认为这不是实现他所需要的最佳方法之一。
正如您所看到的,我们需要在某些条件下更新MyTable
,而不是在另一条件下更新MyTable
。只要有条件允许用户更新MyTable
,我们就不希望多个用户同时更新Begin Transaction
。问题在于编写此过程的方式所有变量都是使用select语句设置的,然后sp_getapplock
开始。
但是考虑到这个过程的结构,最好是执行一个sp_getapplock
过程,只允许一个用户进行更新(考虑到它的结构,这可能适用于这个过程,但是我在那里阅读{{ 1}}可能导致死锁),其他选项是执行可序列化的READ_COMMITED
。
但是在序列化的情况下,这个存储过程不允许其中一个并发用户(例如2)仍然选择col1,col2,col3和col4的旧值并填充@onGoingSession
之类的变量,{当另一个完成更新并释放行时(通过可序列化),{1}}等等那些旧值。自事务完成之后,它就是第二个用户的转向。我确实想阻止其他用户阅读正在修改的行。
我们不应该在声明变量之后立即移动begin transaction,并且在它之后执行可序列化。因此,没有并发用户应该读取旧值并填充变量,而其中一个用户(显然是已经获得行锁的用户)正在更新锁定行但尚未提交。
@timeDiff
答案 0 :(得分:0)
以下内容会将事务简化为单个update
语句,并使用逻辑来更新case
表达式处理的各个列。后处理可处理任何错误并产生预期的各种结果。
create procedure dbo.MyTableProc( @UserId as Char(20) )
as
begin
declare @CounterOfResync as TinyInt;
declare @Error as Int;
declare @ErrorMessage as VarChar(200);
declare @OngoingSession as Bit = 1;
declare @PriorUsername as Char(20);
declare @TimeDiff as SmallInt;
declare @WarningMessage as VarChar(300);
update MyTable
set
@CounterOfResync = Col1,
@PriorUsername = UserId,
@OngoingSession = Col3,
@TimeDiff = DateDiff( minute, Col4, Current_Timestamp ),
UserId = @UserId,
Col2 = case when Col3 = 0 and Col1 > 0 and DateDiff( minute, Col4, Current_Timestamp ) >= 5 then 1 else Col2 end,
Col3 = case when Col1 = 0 and Col3 = 0 then 1 else Col3 end,
Col4 = Current_Timestamp
set @Error = @@Error;
if ( @CounterOfResync = 1 )
if ( @TimeDiff >= 360 )
begin
if ( @Error = 0 )
begin
set @WarningMessage = 'An unfinished session for user ' + @PriorUsername + ' is going on for the past ' +
Cast( @TimeDiff as VarChar(10) ) + ' minutes but updates from ' + @UserId + ' are successful';
RaIsError( @WarningMessage, 7, 1 );
end
else
return @Error;
end
else
begin
if ( @Error = 0 )
begin
set @ErrorMessage = 'A session of updates for '+ @PriorUsername + ' is already in progress concurrent updates are not allowed';
RaIsError( @ErrorMessage, 8, 1 );
end
else
return @Error;
end
else
if ( @OngoingSession = 0 and @CounterOfResync = 0 )
return @Error
else
-- ...
为尝试浏览现有代码并将其转换为陌生人的错误而道歉。我的意图是提供您可能选择遵循的(误)方向,而不是完整的代码。