先謝謝了; 我繼承了一個存儲過程,它在一次調用中增加一條記錄並返回其值。意圖是隻返回一個單一的值,就像一個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'應該是主鍵。 –