1

私は最初にEFコードを使用しています。最近、次のコードを置き換える必要がありました。

User user = userRepository.GetByEmail("some@email.com");

if (user == null)
{
    user = New User { Email = email, CreatedAt = DateTime.Now };

    userRepository.Add(user);
    unitOfWork.Commit();
}

Context.ExecuteSqlCommand("IF NOT EXISTS(SELECT 1 FROM Users WHERE Email = '{0}')
                           INSERT INTO Users(Email, CreatedAt)
                           VALUES ('email', GETDATE())");

この背後にある理由は、何千もの行を追加しようとすると、EFが最初のコードを実行するのに非常に長い時間がかかったためです。これをExecuteSqlCommandに変更することで、その数の行を処理する時間が大幅に短縮されました。

私が今見ている問題(これまでに2回しか発生していません)は、データベースからの次のメッセージです。トランザクション(プロセスID 52)が別のプロセスのロックリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。

これを解決するにはどうすればよいですか?上記のようないくつかの例外を除いて、私のデータアクセスのほとんどはEFを介して行われます。これまでログでデッドロックが発生したことはないので、これはクエリと関係があると思います。

私の質問は次のとおりです。

  1. No LOCKを使用してクエリを作成する方法はありますか?そのクエリはどのように見えますか?
  2. 特定のクエリにNOLOCKを使用するようにEFに指示する方法はありますか?
4

1 に答える 1

0

実際に必要なのは、ロックを防ぐためではなく、テーブルを早くロックすることです。コマンド内の2つのステートメントの間に、他のプロセスが実行されて同じユーザーが挿入されていないことを確認するには、ロックが必要です。(物理ストレージが変更されているため、データを挿入するときは常にロックが必要です。)

これが実際にデッドロックを引き起こしているコマンドであると仮定すると、排他ロックのみを要求するため、以下はそれを解決する必要があります。

Context.ExecuteSqlCommand( "IF NOT EXISTS(SELECT 1 FROM Users WHERE Email ='{0}')INSERT INTO Users(Email、CreatedAt)VALUES('email'、GETDATE())");

于 2012-09-19T22:54:04.843 に答える