我有一个存储过程,将其@id作为输入参数。表的Student主键位于Id_Column和上Count_Column。如果给定的表中存在任何记录id,则我Count_Column从表中选择最大值,并通过将max增大Count_Column1来插入新行,否则值为零。
@id
Student
Id_Column
Count_Column
id
我是从WCF服务中的ado.net代码调用此存储过程的,而此服务是从asp.net Web应用程序调用的。
在正常情况下,该存储过程可以正常工作,但是当多个用户同时调用该存储过程时,就会发生主键冲突问题,在同样的情况下,我也通过使应用程序成为多线程而重现了这种情况。我知道这个问题与并发性有关,最初我是with(nolock)在选择查询中使用的,但现在已经删除了它。
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
尝试类似……
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。
Identity
Sequence Object