先谢谢了; 我继承了一个存储过程,它在一次调用中增加一条记录并返回其值。意图是只返回一个单一的值,就像一个Identity()列。 这里是存储过程:SQL Server存储过程更新记录和返回值同时
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
不幸的是,这是很老的代码,我不能修改应用程序中实现身份()。这在多年以来一直由ColdFusion应用程序访问的生产中起作用。它现在被一个C#应用程序调用,我们正在看到什么是线程问题。我需要在SQL中解决这个问题,而不是在CF或.NET中解决这个问题,因为这个过程在两个应用程序中的很多位置被调用。
他们获得返回,如果他们住在独立的环境中相同的值。我应该补充一点,大多数时候它的工作方式都是按照预期工作的,但并非总是如此。我的猜测是,当它在每个应用程序中被调用完全相同的毫秒时,它只在严重负载下工作。
我不想做一些锁的,因为这件事情被调用数千每小时倍。恐怕我们最终会遇到僵局问题。
为了清楚起见,这里是CF和C#的电话:
<CFFUNCTION name="getNextId" returntype="numeric" access="public">
<CFARGUMENT name="keyTableName" type="string" required="yes" >
<CFARGUMENT name="dbSource" type="string" required="yes" >
<cfstoredproc procedure="sp_GetNextKey" datasource="#ARGUMENTS.dbSource#" returnCode="No">
<cfprocparam type="OUT" CFSQLType="CF_SQL_INTEGER" variable="RetVal">
<cfprocparam type="IN" CFSQLType="CF_SQL_VARCHAR" value="#UCase(ARGUMENTS.keyTableName)#" maxlength="250">
</cfstoredproc>
<cfquery name="ab" datasource="#ARGUMENTS.dbSource#">
SET ARITHABORT ON
</cfquery>
<cfreturn RetVal >
</CFFUNCTION>
C#:
SqlCommand cmd = new SqlCommand("sp_GetNextKey", conn);
cmd.CommandType = CommandType.StoredProcedure;
var outParam = new SqlParameter("@RetVal", SqlDbType.Int);
outParam.Direction = ParameterDirection.Output;
outParam.Size = 128;
cmd.Parameters.Add(outParam);
cmd.Parameters.Add("@Name", SqlDbType.VarChar);
cmd.Parameters["@Name"].Value = tableName;
conn.Open();
cmd.ExecuteNonQuery();
//get the return value
retVal = Convert.ToInt32(cmd.Parameters["@RetVal"].Value);
conn.Close();
是什么可以让这件事为任何应用程序返回一个唯一值的最佳方法叫它?
基础上的评论,我们尝试了这一点,但它并没有改变结果:
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 PROCEDURE [dbo].[sp_GetNextKey] @RetVal int OUTPUT, @Name varchar(250) AS BEGIN TRANSACTION EXEC sp_getapplock @LockMode = 'Shared', @Resource = 'Keys'; UPDATE Keys WITH (ROWLOCK) SET @RetVal = Key_Next = Key_Next + 1 FROM Keys WHERE Key_Table = @Name EXEC sp_releaseapplock @Resource = 'Keys' COMMIT TRANSACTION
你什么意思,你不能修改使用身份申请?你只能修改sql server中的表,并且可以将seed设置为max(Key)值。或者,也许你想看看NEWID(),但无论哪种方式我很困惑,为什么应用程序会被修改。我也猜测Keys对它没有独特的约束? – scsimon
查看隔离级别和ROWLOCK。 – pmbAustin
proc不应该有并发问题,但可以重构为'SET @RetVal = Key_Next = Key_Next + 1'。重要的是,'KeyTable'应该是主键。 –