一尘不染

如何解决SQL Server存储过程中的并发插入问题

sql

我有一个存储过程,将其@id作为输入参数。表的Student主键位于Id_Column和上Count_Column。如果给定的表中存在任何记录id,则我Count_Column从表中选择最大值,并通过将max增大Count_Column1来插入新行,否则值为零。

我是从WCF服务中的ado.net代码调用此存储过程的,而此服务是从asp.net Web应用程序调用的。

在正常情况下,该存储过程可以正常工作,但是当多个用户同时调用该存储过程时,就会发生主键冲突问题,在同样的情况下,我也通过使应用程序成为多线程而重现了这种情况。我知道这个问题与并发性有关,最初我是with(nolock)在选择查询中使用的,但现在已经删除了它。

我已经读过某个地方,可以通过设置事务隔离级别来解决该问题,但是当我尝试时,却遇到了回滚事务异常的情况。

请让我知道此问题的任何有效解决方案。

declare @iCount = 0;

if exists(select 'x' from Student with(nolock) where Id_Column = @iId)
begin
    set @iCount = (select max(Count_Column) 
                   from Student
                   where Id_Column = @iId)
end

insert into Student
values(@id, @iCount + 1);

第二个解决方案:

begin try
set transaction isolation level serializable
begin transaction
    declare @iCount = 0;

    if exists(select 'x' from from Student with(nolock) where Id_Column = @iId)
    begin
        set @iCount = (select max(Count_Column) 
                       from Student
                       where Id_Column = @iId)
    end

    insert into Student
    values(@id, @iCount + 1);

    commit transaction
end try
begin catch
    rollback transaction
end catch

阅读 260

收藏
2021-05-16

共1个答案

一尘不染

尝试类似……

BEGIN TRY
  BEGIN TRANSACTION;
     DECLARE @iCount INT;

    IF EXISTS(SELECT 1 FROM Student WITH(UPDLOCK,HOLDLOCK) WHERE Id_Column = @iId)
    BEGIN

      select @iCount = ISNULL(max(Count_Column), 0) + 1 
      from Student WITH(UPDLOCK,HOLDLOCK) where Id_Column = @iId

         insert into Student
         values(@id, @iCount);
    END
  COMMIT TRANSACTION;
END TRY

BEGIN CATCH

 IF (@@TRANCOUNT <> 0)
     ROLLBACK TRANSACTION;

END CATCH

重要的提示

您实际上应该Identity在此处使用column来处理自动增量值。如果您使用的是sql server
2012或更高版本,则还有另一种选择也是使用Sequence Objectauto-increment。

2021-05-16