c#与multithreading服务器中的entity framework一起工作
在multithreading服务器中使用entity framework的最佳做法是什么? 我正在使用entity frameworkObjectContext
来pipe理我所有的数据库操作,现在我知道这个上下文不是线程安全的,所以现在当我需要使用它来执行一些数据库操作时,我用lock
语句把它包围起来是安全的。 这是我应该怎么做?
在multithreading环境中为entity framework提供一些快速build议:
- 不要对
locks
使用唯一的上下文(没有单例模式) - 提供无状态的服务 (你需要实例化和处理每个请求一个上下文 )
- 尽可能缩短上下文寿命
- 做一个并发控制系统 。 乐观并发可以通过Entity Framework轻松实现(操作方法 )。 这将确保您在使用不是最新的实体时不会覆盖数据库中的更改
我有点困惑,我认为使用一个上下文是好的,因为它有一些捕捉我相信,所以当我在连续的请求中处理相同的实体时,使用相同的上下文,然后创build一个新的上下文每次。 那么,为什么它会像这样使用它,如果它更慢,而且还不是线程安全的?
你只能使用一个上下文,但是除非你真的知道你在做什么,否则它是强烈的沮丧。
我发现这种方法经常发生两个主要问题:
-
你将使用大量的内存,因为你的上下文永远不会被释放,所有被操纵的实体将被caching在内存中(每个出现在查询结果中的实体都被caching)。
-
如果您修改其他程序/上下文中的数据,则会遇到许多并发问题。 例如,如果直接在数据库中修改某些内容,并且关联的实体已被caching在唯一的上下文对象中,则上下文将不会知道直接在数据库中进行的修改 。 您将使用一个不是最新的caching实体,相信我,这将导致难以find和解决的问题。
也不要担心使用多个上下文的性能 :在90%的用例中,为每个请求创build/部署新上下文的开销几乎是微不足道的。 请记住,创build新的上下文不一定会创build一个到数据库的新连接(因为数据库通常使用连接池)。
这是我应该怎么做?
不可以。至less,每个线程使用上下文,但我强烈build议您将上下文视为工作单元,从而使用每个线程的每个工作单元的上下文。
您需要为您的应用程序定义“工作单元”。 但不要使用lock
来跨多个线程使用上下文。 它不缩放。
您将ObjectContext看作是一个非常昂贵的实体,所以您只需实例化一次,然后将其视为“外观”。 没有必要这样做。 如果没有其他原因,连接被集中在引擎盖下面,并且花费非常less(微秒 – 可能更less?)来完全设置“链对象”来使用ObjectContext抽象。
ObjectContext很像直接使用SqlConnection等,被devise成与“尽可能晚实例化并尽快转储”的方法一起使用。
EF为您提供了一些安全性,因为您可以在提交之前testing是否有最新的对象(乐观并发)。 这本身并不意味着“线程安全”,但是如果遵守这些规则,它也会达到同样的效果。
通常,ObjectContext不应该在整个应用程序中全局使用。 你应该经常创build新的ObjectContexts并处理旧的。 他们当然也不是线程安全的。 如果您继续使用相同的ObjectContext(取决于您的应用程序的生命周期),那么如果您修改大量数据,则很容易发生内存不足exception,因为您更改的实体的引用由对象上下文保存。
我为每个primefaces操作创build一个新的上下文并处理上下文。 据我所知,从书籍和文章中,我更愿意尽可能缩短上下文的生活时间。 (但它取决于你的方法和你的应用程序types,WinForm或Web)
请在伟大的文章中find更多信息。 http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management
好书: http : //books.google.co.th/books?id=Io7hHlVN3qQC&pg=PA580&lpg=PA580&dq=DbContext+lifetime+for+desktop+application&source=bl&ots=ogCOomQwEE&sig=At3G1Y6AbbJH7OHxgm-ZvJo0Yt8&hl=th&ei=rSlzTrjAIovOrQeD2LCuCg&sa=X&oi=book_result&ct =导致&resnum = 2&VED = 0CCgQ6AEwAQ#v = onepage&q&F =假
在WinForm绑定场景中的Datacontext生命周期的现有讨论
我在multithreading环境中使用entity framework,任何线程,用户界面和后台(STA和MTA)都可以同时更新同一个数据库。 我通过在任何新的后台线程开始使用时重新创build实体连接来解决这个问题。 检查实体连接实例ConnectionString显示一个读者guid,我假设它用于链接常见的连接实例。 通过重新创build实体连接,每个线程的guid值都不相同,并且不会出现冲突。 请注意,组件只需与模型所在的组件相同。
public static EntityConnection GetEntityConnection( // Build the connection string. var sqlBuilder = new SqlConnectionStringBuilder(); sqlBuilder.DataSource = serverName; sqlBuilder.InitialCatalog = databaseName; sqlBuilder.MultipleActiveResultSets = true; ... var providerString = sqlBuilder.ToString(); var sqlConnection = new SqlConnection(providerString); // Build the emtity connection. Assembly metadataAssembly = Assembly.GetExecutingAssembly(); Assembly[] metadataAssemblies = { metadataAssembly }; var metadataBase = @"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl"; var dbModelMetadata = String.Format(metadataBase, objectContextTypeModelName); // eg: "res://*/Models.MyDatabaseModel.csdl|res://*/Models.MyDatabaseModel.ssdl|res://*/Models.MyDatabaseModel.msl" var modelMetadataPaths = modelMetadata.Split('|'); var metadataWorkspace = new MetadataWorkspace(modelMetadataPaths, metadataAssemblies); var entityDbConnection = new EntityConnection(metadataWorkspace, sqlConnection); return entityDbConnection;