如何解决SQL Server存储过程中的并发插入问题 [英] How to solve concurrency Insert issue in SQL Server stored procedure

查看:103
本文介绍了如何解决SQL Server存储过程中的并发插入问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个存储过程,它以 @id 作为输入参数.表 Student 的主键位于 Id_Column Count_Column 上.如果表中存在给定 id 的任何记录,那么我从表中选择最大 Count_Column ,并通过将max Count_Column 递增值为零的其他1个.

I have a stored procedure which takes @id as input parameter. Table Student has primary key on Id_Column and Count_Column. If any record is present in table for the given id, then I select the max Count_Column from table and insert new row by incrementing max Count_Column by 1 else with zero value.

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

I'm calling this stored procedure from ado.net code in a WCF service and this service is called from an asp.net web application.

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

This stored procedure works fine in normal cases, but when multiple users calls it at same time, primary key violation issue happen, same case I have reproduced by making application multithreaded too. I know that this issue is related to concurrency, initially I was using with(nolock) in select query, but I have removed this now.

我读过一些地方,可以通过设置事务隔离级别来解决它,但是当我尝试时,我遇到了一些回滚事务异常的情况.

Somewhere I have read that by setting transaction isolation level it can be solved but when I tried I am some getting rollback transaction exception.

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

Please let me know any efficient solution for this problem.

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

推荐答案

尝试类似的方法……

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 列来处理自动增量值.如果您使用的是sql server 2012或更高版本,则还可以选择使用 Sequence Object 还是自动增量.

You should really be using Identity column here to handle the auto-increment value. If you are using sql server 2012 or later you also have another option of using Sequence Object also an auto-increment .

这篇关于如何解决SQL Server存储过程中的并发插入问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆