C# SQL Server存储过程同时更新记录和返回值

C# SQL Server存储过程同时更新记录和返回值,c#,sql-server,stored-procedures,coldfusion,C#,Sql Server,Stored Procedures,Coldfusion,提前感谢; 我继承了一个存储过程,它递增一条记录并在一次调用中返回其值。其目的是只返回一个值,就像Identity()列一样。 以下是存储的进程: ALTER PROCEDURE [dbo].[sp_GetNextKey] @RetVal int OUTPUT, @Name varchar(250) AS UPDATE Keys SET Key_Next = Key_Next + 1, @RetVal = Key_Next + 1 FROM Keys WHE

提前感谢; 我继承了一个存储过程,它递增一条记录并在一次调用中返回其值。其目的是只返回一个值,就像Identity()列一样。 以下是存储的进程:

ALTER PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  UPDATE Keys
  SET Key_Next = Key_Next + 1,
       @RetVal = Key_Next + 1
  FROM Keys
  WHERE Key_Table = @Name
不幸的是,这是非常旧的代码,我无法修改应用程序以实现Identity()。这已经在生产中运行多年,仅通过ColdFusion应用程序访问。它现在被一个C#应用程序调用,我们得到了一个线程问题。我需要在SQL中解决这个问题,而不是在CF或.NET中,因为在这两个应用程序中调用这个过程的位置很多

他们得到的返回值与生活在独立环境中的返回值相同。我应该补充一个事实,它在大多数情况下都能像预期的那样工作,但并非总是如此。我的猜测是,只有在每个应用程序中以完全相同的毫秒调用它时,它才处于严重负载下

我不想做某种锁,因为这东西每小时被称为数千次。恐怕我们最终会遇到僵局问题

为清楚起见,以下是CF和C中的调用:

什么是允许这个东西为任何调用它的应用程序返回唯一值的最佳方法

根据评论,我们尝试了这种方法,但没有改变结果:

ALTER 
PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  UPDATE Keys
  WITH (ROWLOCK)
  SET @RetVal = Key_Next = Key_Next + 1
  FROM Keys
  WHERE Key_Table = @Name
也尝试过,但没有成功:
ALTER
过程[dbo]。[sp_GetNextKey]
@RetVal int输出,
@名称varchar(250)
作为
开始交易
EXEC sp_getapplock@LockMode='Shared',@Resource='Keys';
更新密钥
带(行锁)
设置@RetVal=Key\u Next=Key\u Next+1
钥匙
其中Key_Table=@Name
EXEC sp_releaseapplock@Resource='Keys'
提交事务

试试

ALTER PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  UPDATE Keys
  SET @RetVal = Key_Next = Key_Next + 1
  FROM Keys
  WHERE Key_Table = @Name
您需要在更新字段的同时设置变量的值

试试看

ALTER PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  UPDATE Keys
  SET @RetVal = Key_Next = Key_Next + 1
  FROM Keys
  WHERE Key_Table = @Name
您需要在更新字段的同时设置变量的值

试试这个:

ALTER PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  BEGIN TRAN
      SELECT @RetVal = MAX(Key_Next) + 1 FROM Keys WHERE Key_Table = @Name
      UPDATE Keys SET Key_Next = @RetVal WHERE Key_Table = @Name
  COMMIT
这是有意将两个操作拆分为单独的语句,并将它们包装在事务中,以便使用正确的锁并保持一致性

试试这个:

ALTER PROCEDURE [dbo].[sp_GetNextKey]
  @RetVal int OUTPUT,
  @Name varchar(250)
AS
  BEGIN TRAN
      SELECT @RetVal = MAX(Key_Next) + 1 FROM Keys WHERE Key_Table = @Name
      UPDATE Keys SET Key_Next = @RetVal WHERE Key_Table = @Name
  COMMIT

这是有意将两个操作拆分为单独的语句,并将它们包装在事务中,以便使用正确的锁并保持一致性

函数中的Coldfusion并发错误:

如果包含ColdFusion getNextId函数的组件缓存在内存中,则可能会导致您的问题,因为非显式作用域变量(如RetVal变量)的默认作用域位于组件级别,而不是不熟悉CF的人可能认为的函数,这使得它对组件是全局的。在函数中的参数后面添加以下行,使其不再易受并发问题的影响(将变量定义为函数的局部变量)


或者,您可以通过在变量前面加上
local.
everyhave来显式地将变量范围限定到函数中。例如:
local.RetVal
。(适用于CF9+)

功能中的Coldfusion并发错误:

如果包含ColdFusion getNextId函数的组件缓存在内存中,则可能会导致您的问题,因为非显式作用域变量(如RetVal变量)的默认作用域位于组件级别,而不是不熟悉CF的人可能认为的函数,这使得它对组件是全局的。在函数中的参数后面添加以下行,使其不再易受并发问题的影响(将变量定义为函数的局部变量)


或者,您可以通过在变量前面加上
local.
everyhave来显式地将变量范围限定到函数中。例如:
local.RetVal
。(适用于CF9+)

您不能修改应用程序以使用标识是什么意思?您只能在sql server中修改表,并且可以将种子设置为max(Key)值。或者,您可能想查看NEWID(),但无论如何,我都不明白为什么要修改应用程序。我还猜测键没有唯一的约束?查看隔离级别和行锁。该进程不应该有并发问题,但可以重构为
SET@RetVal=Key\u Next=Key\u Next+1
。重要的是,
KeyTable
应该是主键。也许您可以实现一个序列而不是键表。然后,您只需更改过程以增加序列并返回值。与您正在执行的操作类似,但使用序列会更加健壮。
outparam.Size=128看起来错误,可能只是可以删除。您不能修改应用程序以使用标识是什么意思?您只能在sql server中修改表,并且可以将种子设置为max(Key)值。或者,您可能想查看NEWID(),但无论如何,我都不明白为什么要修改应用程序。我还猜测键没有唯一的约束?查看隔离级别和行锁。该进程不应该有并发问题,但可以重构为
SET@RetVal=Key\u Next=Key\u Next+1
。重要的是,
KeyTable
应该是主键。也许您可以实现一个序列而不是键表。然后,您只需更改过程以增加序列并返回值。与您正在执行的操作类似,但使用序列会更加健壮。
outparam.Size=128
看起来错误,可能只是被删除。这与问题中发布的有问题的代码有何不同?在代码中,您试图像在select语句中那样设置变量值,但在更新字段时,需要在