我在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
答案 0 :(得分:1)
您遇到的问题是因为并发请求都是从表dbo.PLAN_POL_NO获得相同的POL_ID_SEQ。
您的问题有多种解决方案,但我可以想到两个可能对您有所帮助,并且不需要/小代码更改:
在存储过程中,您可以使用以下内容:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
这将确保在SP块期间读取/修改的任何数据在事务上是一致的,并避免幻像读取,重复记录等。它可能会产生更高的死锁,如果在整个应用程序中对这些表进行了大量查询/更新,则可能有一整套新问题。
这样的事情:
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“获取”序列号。目前的设计充其量是脆弱的。