2012-03-28 14 views
2

私は以下のストアドプロシージャを持っています。それは名前を取得するためのものです。名前がテーブルに存在する場合は、対応するIDを返します。まだ存在しない場合は、新しいIDを作成し、それを新しいIDでテーブルに追加します。トランザクション間の同期方法

問題は、同じ名前(まだテーブルにはない)を使用する複数のスレッドでこれを実行すると、後で複数のIDが入力されることがあります。

私が望むのは、別のトランザクションが実行されている間にトランザクションがブロックされ、その名前がデータベースに1回だけ入ることです。

使用する必要がある分離レベルまたは選択ヒントはありますか?これを行う別の方法がありますか?

CREATE PROCEDURE [dbo].[sp_createID] 
@name varchar(max) 
AS 
BEGIN 
SET NOCOUNT ON; 
BEGIN TRAN 
    DECLARE @id as int 
    SELECT @id=Id FROM MyTbl WHERE [email protected] 
    IF @id IS NULL 
    BEGIN 
     UPDATE idGeneratorTbl SET lastkey=lastkey+1 
     SELECT @id=lastKey FROM idGeneratorTbl 
     INSERT INTO MyTbl VALUES(@id, @name) 
    END 
    SELECT @id 
COMMIT   
END 

答えて

1

両方のprocsは、あなたが望むものを達成するために同じトランザクションでなければなりません。

これは、[sp_generateNewId]プロシージャのトランザクションコントロールを削除することで実現できます。

FYI、あなたはなぜあなたはちょうど私が余分なトランザクション制御を削除するには、sp_createIDコードにsp_generateNewIdコードを移動IDENTITYフィールド

+0

を作成しない、鍵生成を心配する必要はありません。残念ながら、これは役に立たない。 私はIDENTITYフィールドを認識しています。私たちは新しいテーブルでそれを使用していますが、これは私たちの製品に長年携わってきた古いテーブルなので、現時点では変更したくありません。 –

+0

thats weird、トランザクションがコミットされた後ではなく、トランザクションがMyTblテーブルの読み込み後にロックを解放していると思います。 TABLOCKXまたはXLOCKを使用して「SELECT @ id = Id FROM MyTbl WHERE name = @ name」を実行してみてください。http://msdn.microsoft.com/en-us/library/ms187373.aspx – Diego

+0

@Shaharこれらはネストされていますトランザクション。内部コミットはまったくコミットしないので、すべてのロックは外部コミットまで保持されます。 –

関連する問題