質問

私は(数字の他のタイプの間で)入射番号を使用するアプリケーションを有しています。これらの数値は、カウンタの現在の値を含む、「Number_Setup」と呼ばれるテーブルに格納されています。

場合アプリは新しいインシデント、それnumber_setupテーブルを生成し(カウンタは、毎週、毎日リセットすることができる、などとINTのように格納されている)が必要数カウンタ行を取得します。次に、カウンタをincremenets、新しい値を持つ行を更新します。

アプリケーションは、マルチユーザー(約100任意の時点でユーザ、ならびに実行し、各100入射レコードの要求事件番号をつかむSQLジョブ)です。インシデントテーブルは、彼らが重複してはならないいくつかの重複したインシデント番号を持っています。

ストアドプロシージャは、次のカウンタを取得するために使用されます。

SELECT @Counter = counter, @ShareId=share_id, @Id=id
FROM Number_Setup
WHERE LinkTo_ID=@LinkToId
AND Counter_Type='I'

IF isnull(@ShareId,0) > 0
BEGIN 
    -- use parent counter
    SELECT @Counter = counter, @ID=id
    FROM Number_Setup
    WHERE Id=@ShareID
END

SELECT @NewCounter = @Counter + 1

UPDATE Number_Setup SET Counter = @NewCounter
WHERE id=@Id

私は今、トランザクションとそのブロックを囲まれましたが、私はまだ共有ロックがあると思うと、それは「100%は、問題を修正します全くわからないんだけど、そうカウンタは、とにかく読むことができます。

おそらく、私はカウンターが更新されていないことを確認することができ、更新文の

UPDATE Number_Setup SET Counter = @NewCounter
WHERE Counter = @Counter
IF @@ERROR = 0 AND @@ROWCOUNT > 0 
    COMMIT TRANSACTION
ELSE
    ROLLBACK TRANSACTION

私は、これは金融などのアプリで請求書番号
に共通の問題であると確信しています 私はどちらかのコードのロジックを入れて、そのレベルでのロックを使用することはできません。 私はまた、HOLDLOCKでロックされてきましたが、私はそれのアプリケーションのかわかりません。それは2つのSELECT文の上に置くべきでしょうか?

どのように私は何の重複が作成されていないことを確認することができますか?

役に立ちましたか?

解決

トリックカウンタの更新を行うと、単一のアトミック操作で読み取ることである

UPDATE Number_Setup SET Counter = Counter+1
OUTPUT INSERTED.Counter 
WHERE id=@Id;

このしかしは@NewCounterに新しいカウンターを割り当てるが、その代わりにクライアントに結果セットとして返していません。あなたはそれを割り当てることがある場合は、出力に新しいカウンタINTOを中間テーブル変数を使用します:

declare @NewCounter int;
declare @tabCounter table (NewCounter int);
UPDATE Number_Setup SET Counter = Counter+1
OUTPUT INSERTED.Counter INTO @tabCounter (NewCounter)
WHERE id=@Id
SELECT @NewCounter = NewCounter FROM @tabCounter;

これは、カウンターの増分は、原子作るの問題を解決します。あなたは間違ったリンクへのアイテムのカウンタをインクリメントすることができますので、LinkTo_Idとshare_idはまだ最初の選択後に更新することができますので、あなたはまだあなたの手順で他の競合状態を持っているが、それはまた依存することは、ちょうどこのコードサンプルから解決することはできませんactualy shared_idを更新コードに及び/又はLinkTo_Id。

ところで、あなたは、名前のhabbit一貫場合と、あなたのフィールドに取得する必要があります。彼らはをした場合のあなたがを一貫して命名されているのT-SQLコード内の完全一致のケースを使用する必要があります。あなたのスクリプトは、大文字と小文字が区別照合サーバにデプロイし、あなたのスクリプトが豊富に続くフィールド/テーブル名エラーの正確な場合と一致しない場合は、大文字小文字を区別しない照合サーバを持っているという理由だけで今も元気に実行ます。

他のヒント

あなたはあなたの一意の識別子としてのGUIDの代わりに、自動インクリメントを使用してみましたが?

あなたがみとめレコードを取得するあなたの仕事を変更するablityを持っている場合は、あなたのカウンターがID列であるように、

、私は考え方を変えるでしょう。あなたは次のレコードを取得するときに次に、あなただけの挿入を行うと、テーブルの@@ IDを取得することができます。それはあなたが最大の番号を取得することを確実にするでしょう。また、あなたが身元をリセットしたいときだけテーブルを更新するのではなく、カウンタをリセットするためにdbccReseedを行う必要があります。唯一の問題は、あなたがアイデンティティのグループを得るためにあなたのSQLジョブの一部として、100かそこらの挿入を行う必要があるだろうということです。それはあまりにも多くのオーバーヘッドもなく、ID列を使用すると、ユニークな番号を取得するguarenteedな方法であることがあります。

私は何かが欠けているかもしれないが、あなたはすでにほとんどのデータベースによって解決された技術を改革しようとしているように思えます。

の代わりにNumber_Setupテーブルの「カウンタ」欄からの読み取りと更新の、あなたは自分のカウンターの自動増分主キーを使用していない理由は?あなたは主キーの重複値を持つことは決してないだろう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top