【问题标题】:Entity Framework DbContext and thread safety实体框架 DbContext 和线程安全
【发布时间】:2015-09-05 08:43:46
【问题描述】:

我需要在一个事务中更新我的数据库中的几个表,我读到使用DbContext.SaveChanges 应该是这样做的方法。

但是我也读到DbContext 的生命周期应该尽可能短,因为随着时间的推移它会随着加载更多实体而增长。

我还读到,为了使其线程安全,每个操作都应该有自己的DbContext

我是否应该为每个要更改的表设置一个DbContext 并在每个DbContext 上调用SaveChanges?最后一次SaveChanges 调用不会覆盖之前调用的更改吗?

最好的方法是什么? (我需要这个做网站)

【问题讨论】:

  • 如果您想在单个事务中完成所有操作,那么单个 DbContext 就可以了。无需担心线程安全,因为您需要按顺序执行所有操作。
  • @DavidG :但是如果 2 个用户尝试同时使用同一个 DbContext 怎么办?它不会导致竞争条件吗?
  • 你不应该允许这种情况发生。 DbContext 不适合那样使用,如果你尝试,它会做一些非常奇怪的事情!
  • @DavidG:这就是为什么我问我是否应该为每个动作使用 DbContext。我可以在使用时使用一个简单的互斥锁,但是我可能会失去一些可能内置的优化......
  • 你真的应该展示一些代码。当您谈论共享上下文和需要互斥体时,我感觉您正在做一些非常糟糕的事情,但是如果我们看不到确切发生的情况,我们无法给出任何明确的建议。

标签: c# asp.net-mvc multithreading entity-framework


【解决方案1】:

Entity Framework is not thread-safeAn MVC controller is instantiated per request。因此,如果您为每个请求使用一个 DbContext,那么只要您不在控制器操作中手动生成线程(无论如何您都不应该这样做),您就是安全的。

现在,如果您的应用程序中有并发,例如一个预订系统,其中多个用户可以访问相同的稀缺资源(例如门票),那么您将必须实现逻辑你自己。无论如何,没有线程安全可以帮助您。

这就是为什么要求您提供 cmets 中的代码,因为一般解释线程安全性过于宽泛,可能不适用于您的情况。

【讨论】:

    【解决方案2】:

    简单的方法是,每个请求都有一个 DbContext,ASP.NET MVC 确保所有线程安全,ASP.NET MVC 中的每个控制器实例对每个请求都是隔离的,您不必担心竞争条件。只要你不创建线程,只是简单地使用单个 DbContext 在 action 方法中进行数据转换,你不会有任何问题。

    基本上 DbContext 什么都不做,它只是将 SQL 查询排队到目标数据库,它是处理多线程、竞争条件的数据库。为了保护您的数据,您应该使用事务并在数据库中添加验证以确保正确保存它们

    public abstract class DbContextController : Controller{
    
        public AppDbContext  DB { get; private set;}
    
        public DbContextController(){
            DB = new AppDbContext();
        }
    
        protected override void OnDisposing(bool disposing){
            DB.Dispose();
        }
    
    }
    

    如果你从DbContextController继承任何类并在控制器的整个生命周期中使用DB,你不会有任何问题。

    public ActionResult ProcessProducts(){
        foreach(var p in DB.Products){
           p.Processed = true;
           foreach(var order in p.Orders){
              order.Processed = true;
           }
        }
        DB.SaveChanges();
    }
    

    但是,如果您使用以下示例中的任何线程,

    public ActionResult ProcessProducts(){
        Parallel.ForEach(DB.Products, p=>{
             p.Processed = true;
             // this fails, as p.Orders query is fired
             // from same DbContext in multiple threads
             foreach(var order in p.Orders){
                 order.Processed = true;
             }
        });
        DB.SaveChanges(); 
    }
    

    【讨论】:

    • “基本上 DbContext 什么都不做……”爱它!
    猜你喜欢
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多