2009-04-22 18 views
0

ライセンスキー/シリアル番号のSQL Serverテーブルがあります。 テーブル構造は次のようなものです。私のASP.NETアプリケーションを介してシリアル番号プールからシリアル番号をクライアントに割り当てる

[ 
RecordId int, 
LicenceKey string, 
Status int (available, locked, used, expired etc.) 
AssignedTo int (customerId) 
.... 
] 

ユーザーが受け入れるボタンをクリックし、ライセンスを購入することを決定したときに、私は、ユーザーのライセンスキーを確保する必要があります。 私のアプローチは次のようなものです KeysTableからトップ1を選択してください。ステータス=利用可能 更新キーセットステータス=ロック キーをアプリケーションに戻します。

私の懸念は、2つのasp.netスレッドが同じレコードにアクセスし、同じlicencekeyを返す場合です。 このような課題を実行するベストプラクティスは何と思いますか?この種の問題にはよく知られているaproachやパターンがありますか? lock()ステートメントが必要な場合はどこで使用しますか?

私はSql Server 2005、データアクセス用のストアドプロシージャ、DataLayerのBusinessLayerおよびAsp.Net GUIを使用しています。

おかげ

答えて

4

この場合、明示的なロックやトランザクションを使用する必要はないでしょう。

ストアドプロシージャでは、UPDATEステートメントのOUTPUT句を使用して、テーブルを更新して1回のアトミック操作でライセンスキーを取得できます。このような

何か:

UPDATE TOP (1) KeysTable 
SET Status = 'locked' 
OUTPUT INSERTED.LicenseKey 
-- if you want more than one column... 
-- OUTPUT INSERTED.RecordID, INSERTED.LicenseKey 
-- if you want all columns... 
-- OUTPUT INSERTED.* 
WHERE Status = 'available' 
+0

licenceKeyフィールドだけでなく、レコード全体を返したい場合はどうすればいいですか? アップデートTOP(1)KeysTable SETステータス= "ロック" SELECT * FROM KeysTable licenceKeyId = INSERTED.licenceKeyId おかげで – UmutKa

+0

いいえ、あなたは正確にそれを行うことはできません。私はこのようなものを使用することができます。私はそれがどのように行われたかを示すために私の答えを更新します。 – LukeH

+0

非常にいいですが、残念ながら私はこのテーブルのトリガーを持っています。だから私はINTOなしでOUTPUtを使うことはできません。私はINTOを使用する場合、それはまだ原子操作であり、私は期待している、または私はトランザクションの分離を使用する必要があります結果を返しますか? – UmutKa

0

は、私はそうでない場合は、常に競合状態のいくつかの並べ替えが存在しますので、あなたが実際に、あなたはそれのために照会されている同じストアドプロシージャでは使用できないようにキーをマークするべきだと思います。手動でテーブルをロックするのは良い方法ではありません。

2段階のプロセス(航空券の予約など)がある場合は、指定した期間(30分など)キーを予約するというコンセプトを導入して、新しいキーを照会するときに、あなたはそれを同時に予約します。

EDIT:データベースを変更するプロセスが1つだけであることを保証できる場合は、おそらくビジネスロジックのロックが機能しますが、データベースレベルで実行する方がはるかに優れています。これを正しく行うには、@Adam Robinsonが答えたように、トランザクションレベルを設定してデータベース内のトランザクションを使用する必要があります。

+0

これは、すべてで彼の問題に対処していません...彼は同じバッチで選択と更新を実行していますが、(シリアライズ可能なトランザクションのような)ロックを一切持たないので、パラレルバッチが同じ行を選択しないことを保証するものはありません。 –

+0

実際に私はselectキー、更新キーなどのデータアクセスメソッドの周りにlock()ブロックを持つビジネスレイヤーにGetNextAvailableKeyのような静的メソッドを書くつもりです。または、おそらく私はGetNextKeyにSERIALIZABLE分離レベルキーを選択、更新、返し、呼び出しメソッドにlock()ブロックを追加しますか? – UmutKa

+0

申し訳ありませんが、私は私の答えで少し不正確でした。編集をご覧ください。 – Grzenio

1

あなたが話していることを達成するには、シリアライズ可能なトランザクションを使用する必要があります。これを行うには、次のパターンに従います。

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
GO 
BEGIN TRANSACTION 

--Execute select 
--Execute update 

COMMIT TRANSACTION 

しかし、なぜすべてのライセンスキーがあるテーブルを持っていますか?なぜ鍵生成アルゴリズムを持っていないのですか?ユーザがそれを購入したときに新しい鍵を作成するのはなぜですか?

+0

ライセンスキーは私たちのものではありません。私たちは鍵を転売しています。 – UmutKa

0

また、トランザクションに加えてロックを(SQLで)使用して、一度に1つのスレッドのみがアクセスできることを確認することもできます。

私は、アプリケーションのロックがここで助けになると信じています。

関連する問題