简体   繁体   English

实体框架交易锁定

[英]Entity Framework Transaction Locking

I'm seeing some strange race conditions in my webapp that I suspect may be due to the Entity Framework handling read locks in an unexpected way. 我在我的Web应用程序中看到一些奇怪的竞争状况,我怀疑这可能是由于Entity Framework以意外的方式处理读取锁。 When a request is made in my application to any page, I automatically load up the account model which is then stored in my DbContext for the lifetime of the request. 当我在应用程序中对任何页面提出请求时,我会自动加载帐户模型,然后在请求的整个生命周期中将其存储在DbContext中。 Some web pages need to lock the account DB row so I can safely do some other operations without race conditions. 一些网页需要锁定帐户数据库行,这样我就可以安全地进行其他一些操作而不会出现争用条件。 Here's how I'm doing this now... 这就是我现在正在做的事情...

//... code that begins the request and loads the account into context.
// Some pages may run code that looks something like this.
using(var tran = existingCtx.Database.BeginTransaction(IsolationLevel.RepeatableRead))
{
    // Lock customer.
    var act = ctx.Accounts.Find(purchaseFor.ID);
    if (act == null)
        throw new RecordNotFoundException("Unable to find specified customer.");

    DoStuffRelyingOnLock();
    Commit();
}

Will the call find Find(purchaseFor.ID) LOCK the account row in the database even if it's already loaded into context? 呼叫是否会找到Find(purchaseFor.ID)锁定数据库中的帐户行,即使该行已加载到上下文中?

It is good practice that if you are going to handle transactions explicitly, you have your code either commit or rollback. 优良作法是,如果要显式处理事务,则可以提交代码回滚代码。 The MSDN documentation indicates that the explicit rollback is required, but the using statement will fire the Dispose() method, which in turn will rollback any open transaction. MSDN文档指出需要显式回滚,但是using语句将触发Dispose()方法,该方法将回滚任何打开的事务。 For clarity, especially as code tends to get more complex, it is better to handle the rollback explicitly. 为了清楚起见,尤其是当代码趋于变得更加复杂时,最好显式处理回滚。

This OpenStack question has a more thorough explanation in the accepted answer. 这个OpenStack问题在公认的答案中有更详尽的解释。

Will the call find Find(purchaseFor.ID) LOCK the account row in the database even if it's already loaded into context? 呼叫是否会找到Find(purchaseFor.ID)锁定数据库中的帐户行,即使该行已加载到上下文中?

No, it won't. 不,不会。 If the context already has that entity loaded, it won't even talk to the database. 如果上下文已经加载了该实体,它甚至不会与数据库对话。

See what the documentation says about how the Find method works (emphasis mine): 查看文档中有关Find方法如何工作的内容(重点是我的):

Finding entities using primary keys 使用主键查找实体

The Find method on DbSet uses the primary key value to attempt to find an entity tracked by the context. DbSet上的Find方法使用主键值尝试查找上下文跟踪的实体。 If the entity is not found in the context then a query will be sent to the database to find the entity there. 如果在上下文中未找到该实体,则将向数据库发送查询以在该数据库中找到该实体。 Null is returned if the entity is not found in the context or in the database. 如果在上下文或数据库中找不到该实体,则返回Null。

Find is different from using a query in two significant ways: Find与在两种主要方式中使用查询不同:

  • A round-trip to the database will only be made if the entity with the given key is not found in the context. 仅当在上下文中未找到具有给定密钥的实体时,才进行数据库往返。
  • Find will return entities that are in the Added state. Find将返回处于“已Added状态的实体。 That is, Find will return entities that have been added to the context but have not yet been saved to the database. 即,“ Find将返回已添加到上下文但尚未保存到数据库的实体。

Therefore, if you want to ensure that a query to the database is always made for your locking purposes, avoid using Find , and use the Where LINQ method instead. 因此,如果要确保始终出于锁定目的而对数据库进行查询,请避免使用Find ,而应使用Where LINQ方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM