別のアプリケーションで私は悪いデザインに打たれました:複数のスレッドが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()メソッドに適したパターンはありますか?
最善の策は、明示的な包含トランザクションを使用し、カスタム排他ロックを取得して操作全体を保護することです(SELECT
およびCREATE TABLE
) sing sp_getapplock 。システムオブジェクトは、分離レベルの要求を尊重せず、ユーザーテーブルと同じ方法でロックを使用します。
元のコードの競合状態は、スレッドがCREATE TABLE
ステートメントまで到達する前に、複数のスレッドがテーブルが存在しないと結論付けることができることです。
私の推奨は、ベストエフォートのtry/catchを行うことです。必要に応じて、重複したケースを明示的に処理します。それを無視します...
本当の質問:DDLが複数のxactからオンデマンドで実行されるのはなぜですか?通常、アップグレードと移行は深刻な問題であり、専用の時間枠で処理されます...移行(コードファースト)を予期せず開始したくない場合、これらの更新手順の一部は大きなテーブル(サイズ-データ操作...)