web-dev-qa-db-ja.com

CREATE TABLEをロックする

別のアプリケーションで私は悪いデザインに打たれました:複数のスレッドがEnsureDatabaseSchemaExists()メソッドを同時に実行します。これは基本的に次のようになります:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'MyTable') AND type = N'U') BEGIN

    CREATE TABLE MyTable ( ... );

END

ただし、SERIALIZABLEトランザクションで実行された場合でも、このコードはスレッドセーフではないようです(つまり、並列コードはテーブルを複数回作成しようとします)。 SELECTステートメントに強制的にロックを取得させて、別のスレッドがまったく同じSELECTステートメントを実行できないようにする可能性はありますか?

マルチスレッドのEnsureSchemaExists()メソッドに適したパターンはありますか?

19
D.R.

最善の策は、明示的な包含トランザクションを使用し、カスタム排他ロックを取得して操作全体を保護することです(SELECTおよびCREATE TABLEsing sp_getapplock 。システムオブジェクトは、分離レベルの要求を尊重せず、ユーザーテーブルと同じ方法でロックを使用します。

元のコードの競合状態は、スレッドがCREATE TABLEステートメントまで到達する前に、複数のスレッドがテーブルが存在しないと結論付けることができることです。

18
Paul White 9

私の推奨は、ベストエフォートのtry/catchを行うことです。必要に応じて、重複したケースを明示的に処理します。それを無視します...

本当の質問:DDLが複数のxactからオンデマンドで実行されるのはなぜですか?通常、アップグレードと移行は深刻な問題であり、専用の時間枠で処理されます...移行(コードファースト)を予期せず開始したくない場合、これらの更新手順の一部は大きなテーブル(サイズ-データ操作...)

12
Remus Rusanu