web-dev-qa-db-ja.com

EntityFrameworkで行を完全にロックする方法

私は金銭取引を扱っている状況で働いています。

たとえば、ユーザーウォレットのテーブルがあり、その行に残高があります。

UserId; Wallet Id; Balance

現在、当社のWebサイトおよびWebサービスでは、特定のトランザクションが発生するたびに、次のことを行う必要があります。

  1. そのトランザクションを実行するために利用できる十分な資金があることを確認してください。
  2. 残高からトランザクションのコストを差し引きます。

トランザクションの全期間にわたってその行/エンティティをロックするための正しい方法は何ですか?

私が読んだことから、EFがエンティティにマークを付け、それをDBに保存するときにそのマークを比較するいくつかの解決策がありますが、別のユーザー/プログラムがすでに金額を編集している場合はどうなりますか?

EFでこれを達成できますか?そうでない場合、他にどのようなオプションがありますか?

ストアドプロシージャを呼び出すと、行を適切にロックできる可能性があります。これにより、プログラムAがロックされている間、SQL Serverのその行に他のユーザーがアクセスできなくなりますか?

12
Zapnologica

EFには組み込みのロックメカニズムがないため、おそらく次のような生のクエリを使用する必要があります。

using (var scope = new TransactionScope(...))
{
    using (var context = new YourContext(...))
    {
        var wallet = 
            context.ExecuteStoreQuery<UserWallet>("SELECT UserId, WalletId, Balance FROM UserWallets WITH (UPDLOCK) WHERE ...");

        // your logic

        scope.Complete();
    }
}
10
Max Brodin

entity Frameworkのトランザクションに分離レベルを設定して、他の誰もそれを変更できないようにすることができます。

YourDataContext.Database.BeginTransaction(IsolationLevel.RepeatableRead)

RepeatableReadの概要:クエリで使用されるすべてのデータにロックが設定され、他のユーザーがデータを更新できないようにします。繰り返し不可能な読み取りを防ぎますが、ファントム行は引き続き可能です。

4
jen b

トランザクションデータベースの要点は、データの利用者がデータのビューをどの程度分離するかを決定することです。

トランザクションが serialized であるかどうかに関係なく、他の誰かが、変更したがコミットしなかったのと同じデータに対してダーティ読み取りを実行できます。

最初にビューの整合性に関心を持ち、次にそのビューの品質の低下のみを受け入れて、必要であると確信できるシステムパフォーマンスを向上させる必要があります。

すべてをTransactionScopeSerialized分離レベルでラップすれば、個人的には間違いはありません。分離レベルを下げるのは、それが本当に必要であることがわかった場合のみです(つまり、問題が発生した場合は問題ない場合があります)。

誰かがここでこれについて尋ねます: SQL Server:ストアドプロシージャでのダーティリードの防止

3
briantyler