SQL锁定未正确实现

时间:2015-12-29 18:27:28

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

我在Procedure中实现了一个SQL tablockx锁定。当它在一台服务器上运行时工作正常。但是当请求来自两个不同的服务器时,会发生重复的policyNumber。

declare @plantype varchar(max),
@transid varchar(max),
@IsStorySolution varchar(10),
@outPolicyNumber varchar(max) output,
@status int output  -- 0 mean error and 1 means success
)
as
begin

BEGIN TRANSACTION

Declare @policyNumber varchar(100);
Declare @polseqid int;

-- GET POLICY NUMBER ON THE BASIS OF STORY SOLUTION..
IF (UPPER(@IsStorySolution)='Y')
BEGIN
select top 1 @policyNumber=Policy_no  from PLAN_POL_NO with (tablockx, holdlock) where policy_no like '9%' 
and pol_id_seq is null and status='Y';
END


ELSE
BEGIN
select top 1 @policyNumber=pp.Policy_no  from PLAN_POL_NO pp with (tablockx, holdlock) ,PLAN_TYP_MST pt where pp.policy_no  like PT.SERIES+'%'
and pt.PLAN_TYPE in (''+ISNULL(@plantype,'')+'') and pol_id_seq is null and pp.status='Y' 
END

-- GET POL_SEQ_ID NUMBER



select @polseqid=dbo.Sequence();



--WAITFOR DELAY '00:00:03';


set @policyNumber= ISNULL(@policyNumber,'');

-- UPDATE POLICY ID INFORMATION...

Update PLAN_POL_NO  set status='N',TRANSID =@transid , POL_ID_SEQ=ISNULL(@polseqid,0) where Policy_no =@policyNumber 

set @outPolicyNumber=@policyNumber;

if(@@ERROR<>0) begin GOTO Fail end

COMMIT Transaction
set @status=1;
return;
Fail:
If @@TRANCOUNT>0
begin
Rollback transaction
set @status=0;
return; 

这是我调用的函数::

CREATE function [dbo].[Sequence]()      
returns int  
 as    
begin    
declare @POL_ID int

/***************************************
-- Schema name is added with table name in below query 
-- as there are two table with same name (PLAN_POL_NO)
-- on different schema (dbo & eapp).
*****************************************/

select @POL_ID=isnull(MAX(POL_ID_SEQ),2354) from  dbo.PLAN_POL_NO 

return @POL_ID+1

end

2 个答案:

答案 0 :(得分:1)

您遇到的问题是因为并发请求都是从表dbo.PLAN_POL_NO获得相同的POL_ID_SEQ。

您的问题有多种解决方案,但我可以想到两个可能对您有所帮助,并且不需要/小代码更改:

  1. 使用更高的事务隔离级别而不是表提示。
  2. 在存储过程中,您可以使用以下内容:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    

    这将确保在SP块期间读取/修改的任何数据在事务上是一致的,并避免幻像读取,重复记录等。它可能会产生更高的死锁,如果在整个应用程序中对这些表进行了大量查询/更新,则可能有一整套新问题。

    1. 如果序列未更改,请确保对dbo.PLAN_POL_NO的更新成功。如果它已更改,则输出错误(如果更改它意味着并发事务获得了ID并首先完成)
    2. 这样的事情:

      Update dbo.PLAN_POL_NO 
      SET    status      ='N',
             TRANSID     = @transid,
             POL_ID_SEQ  = ISNULL(@polseqid,0)
      WHERE Policy_no = @policyNumber
            AND POL_ID_SEW = @polseqid - 1
      
      IF @@ROWCOUNT <> 1
      BEGIN
         -- Update failed, error out and let the SP rollback the transaction
      END
      

答案 1 :(得分:0)

函数中的WITH (HOLDLOCK)选项可能就足够了。

第一个查询的HOLDLOCK可能会在行或页面级别应用,然后不包括在函数中查询的感兴趣的行。

但是,该功能不可靠,因为它不是自包含的。我想重新设计这个,以便序列可以在返回之前生成AND“获取”序列号。目前的设计充其量是脆弱的。