简体   繁体   English

带有实体框架的ASP .NET MVC 5中的并发

[英]Concurrency in ASP .NET MVC 5 with Entity Framework

I´m working on simple CMS in ASP .NET MVC 5 with Entity Framework. 我正在使用带有实体框架的ASP .NET MVC 5开发简单的CMS。 I have a few questions about concurrency in MVC´s applications. 我对MVC应用程序中的并发性有一些疑问。

First of all - public section of my app (section for users without any authentification): 首先-我应用的公开部分(针对未经身份验证的用户的部分):

  • All data (posts, category informations, tags, documents) are stored in DB (using Entity) 所有数据(帖子,类别信息,标签,文档)都存储在DB中(使用Entity)

  • In controllers for public section, there is only reading or writing data to DB, not deleting or editing 在公共区域控制器中,仅可将数据读取或写入数据库,而不能删除或编辑

So my first question - is it necessary to have some mechanisms to avoid concurrency dangers in public section? 所以我的第一个问题-是否有必要建立一些机制来避免公共场所出现并发危险? Will everything be correct when multiple users will be browsing my website at the same time? 当多个用户同时浏览我的网站时,一切都正确吗?

And then my admin section (authentification needed): 然后是我的管理部分(需要身份验证):

  • There can be multiple users with multiple roles (but in real there will be only few registered users) 可以有多个用户担任多个角色(但实际上只有几个注册用户)
  • Users can create/edit/delete data in DB 用户可以在数据库中创建/编辑/删除数据

I know that some security mechanism are necessary to have safe system, but can you help me how to do this? 我知道某种安全机制对于拥有安全系统是必不可少的,但是您能帮我怎么做吗?

I´m also using this pattern for DbContext in each method, where DB is necessary: 在每种需要DB的方法中,我也在DbContext中使用此模式:

using (var db = new CmsContext()) { // other stuff here }

Instead of one class variable db that is used in all methods. 代替在所有方法中使用的一个类变量db。 Is this right? 这是正确的吗?

Many thanks for answers! 非常感谢您的回答!

is it necessary to have some mechanisms to avoid concurrency dangers in public section? 有必要建立一些机制来避免公共场所出现并发危险吗? Will everything be correct when multiple users will be browsing my website at the same time? 当多个用户同时浏览我的网站时,一切都正确吗?

As far as I can see, concurrency is related with two people editing the same record at the same time. 据我所知,并发与两个人同时编辑同一条记录有关。 Considering that the public section doesn't have any writing method, avoid concurrency mechanism is not necessary, neither is possible. 考虑到公共部分没有任何编写方法,因此避免并发机制是不必要的,也不可能。

I know that some security mechanism are necessary to have safe system, but can you help me how to do this? 我知道某种安全机制对于拥有安全系统是必不可少的,但是您能帮我怎么做吗?

You could write your queries in others classes, like repositories and/or services. 您可以在其他类(例如存储库和/或服务)中编写查询。 Searching for "repository and services entity framework" at google, I found this link http://techbrij.com/service-layer-entity-framework-asp-net-mvc-unit-testing , which sounds very interesting. 在Google搜索“存储库和服务实体框架”时,我发现此链接http://techbrij.com/service-layer-entity-framework-asp-net-mvc-unit-testing ,听起来很有趣。

I´m also using this pattern for DbContext in each method, where DB is necessary: 在每种需要DB的方法中,我也在DbContext中使用此模式:

 using (var db = new CmsContext()) { // other stuff here } 

instead of one class variable db that is used in all methods. 而不是所有方法中都使用一个类变量db。 Is this right? 这是正确的吗?

That's a hard question. 这是一个很难的问题。 It is too hard to say that something is right or wrong these days. 很难说这几天是对还是错。 There are a lot of people, with several different opinions. 人们很多,有不同的看法。 In my opinion, your example is not the best way to do (but it doesn't mean it's incorrect). 在我看来,您的示例并不是最好的方法(但这并不意味着它是错误的)。 When using a repository class, we usually have only one instance of the DbContext. 使用存储库类时,通常通常只有一个DbContext实例。 Take a look at this thread c# entity framework: correct use of DBContext class inside your repository class 看一下这个线程c#实体框架:在存储库类中正确使用DBContext类

Hope this helps! 希望这可以帮助!

For your first question about the users only retrieving/writing data, concurrency won't be a problem. 对于第一个关于用户仅检索/写入数据的问题,并发不会成为问题。 They will never try to update/delete a single row at the same time. 他们绝不会尝试同时更新/删除单个行。 The admin part is another story. 管理部分是另一个故事。 You expect that multiple admin users will be using the database at the same time and this will lead to conditions where admin1 grabs a record, edits it, but when it reinserts the record it was already updated by admin2. 您预计多个admin用户将同时使用数据库,这将导致admin1抓取一条记录,对其进行编辑,但是当它重新插入该记录时,admin2已经对其进行了更新。 There are 2 ways to handle this: 有两种方法可以解决此问题:

  1. Pessimistic concurrency: This means you are using locks on certain records of the database. 悲观并发:这意味着您正在对数据库的某些记录使用锁。 While one process is updating a certain record, those rows get locked and no other processes can edit it meanwhile. 当一个进程正在更新某个记录时,这些行将被锁定,并且其他进程无法同时对其进行编辑。 Unfortunately this is not supported by Entity Framework. 不幸的是,实体框架不支持此功能。
  2. Optimistic concurrency: This is supported by EF and it means you have an extra column in your database with a rowversion. 乐观并发: EF支持的,这意味着您的数据库中有一个带有rowversion的额外列。 When a process tries to reinsert a record, it will first check if the rowversion hasn't changed. 当进程尝试重新插入记录时,它将首先检查行版本是否未更改。 If it's the same, the record gets inserted. 如果相同,则插入记录。 If it's changed the record gets refetched and the values get edited again. 如果更改,则重新获取记录,然后再次编辑值。 Msdn documentation on optimistic concurrency here . 有关乐观并发的Msdn文档,请点击此处

In your code model you can define an extra property with a [TimeStamp] attribute: 在代码模型中,您可以使用[TimeStamp]属性定义一个额外的属性:

[TimeStamp]
public virtual byte[] RowVersion {get; set;}

or in fluent API you can map it like this: 或在流畅的API中,您可以按以下方式进行映射:

modelBuilder<MyEntity>().HasProperty(p => p.RowVersion).IsRowVersion();

You can also use the entire row as 'rowversion' to check for changes, but typically an extra column is used. 您还可以将整个行用作“ 行版本 ”以检查更改,但是通常使用额外的一列。 Otherwise if you want to update just 1 field you'd have to send the whole row to the database because it's needed to check the rowversion. 否则,如果您只想更新1个字段,则必须将整行发送到数据库,因为需要检查行版本。 Also note that [TimeStamp] will only work for a byte array, if you want to use another type you have to use the [ConcurrencyCheck] attribute. 另请注意, [TimeStamp]仅适用于字节数组,如果要使用其他类型,则必须使用[ConcurrencyCheck]属性。 If you use the entire row as a rowversion you have to apply this attribute to all your properties. 如果将整行用作行版本,则必须将此属性应用于所有属性。

First of all, you should understand all the cases when the concurrency can lead to exceptions. 首先,您应该了解并发会导致异常的所有情况。 Some common cases, which are usually about the relations and contracts. 一些常见的情况通常与关系和合同有关。

  • Writes and Updates: 编写和更新:

    • A table contains some unique constraint, so you check if an entity exists, and tries to create one if it doesn't. 一个表包含一些唯一约束,因此您检查一个实体是否存在,如果不存在则尝试创建一个。 Now two concurrent actions performs the check, both get empty result, and both tries to create the entity. 现在,两个并发操作将执行检查,都将得到空结果,并且都尝试创建该实体。 One action will fail with an exception, while the other one got more luck, and created the entity first. 一个动作将失败,但有一个异常,而另一个动作会带来更多的运气,并首先创建实体。

    • A table contains foreign key: by creating new entity, some other action have removed the dependent entry. 一个表包含外键:通过创建新实体,其他一些操作已删除了依赖项。 As a result - exception. 结果-例外。

Concurrent updating of any scalar values wont cause any exceptions, but the last one wins. 同时更新任何标量值不会导致任何异常,但最后一个会获胜。

So you have to consider the structure of your app/db and scenarios and decide if you want to do something to prevent the uncontrolled concurrent updates/writes. 因此,您必须考虑应用程序/数据库和方案的结构,并确定是否要采取某些措施来防止不受控制的并发更新/写入。

What you can do against? 您可以做什么?

Locks

public class FooService {
    private static object Obj = new object();
    public void Create(Foo foo) {
        lock (Obj) {
            // check + create
        }
    }
}

The problem here could be if you have multiple instances, as it is server level lock only. 这里的问题可能是如果您有多个实例,因为它仅是服务器级别的锁定。

Transactions 交易

Database locks 数据库锁

using (var ctx = new DbCtx) {
    ctx.Database.Connection.Open();
    using (var transaction = ctx.Database.BeginTransaction(IsolationLevel.Serializable))
    {
        try {
            // check + update
            transaction.Commit();
        }
        catch (Exception) {
            transaction.Rollback();
        }
    }
    ctx.Database.Connection.Close();
}

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

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