一、背景

  我们知道,为了防止并发而出现脏读脏写的情况,可以使用Lock语句关键字,这属于悲观并发控制的一种技术,,但在分布式站点下,锁的作用几乎不存在,因为虽然锁住了A服务器的实例对象,但B服务器上的锁是不知道的A服务器上锁的情况的,所以,面对分布式站点、单一数据库这种架构,我们可以使用EntityFramework的乐观并发控制来解决这个问题,EF对并发控制有不管控和乐观并发控制两种,默认情况是不管控,但EF不支持悲观并发。
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
 

二、悲观并发和乐观并发

悲观并发:比如有两个用户A,B,同时登录系统修改一个文档,如果A先进入修改,则系统会把该文档锁住,B就没办法打开了,只有等A修改完,完全退出的时候B才能进入修改。

乐观并发:同上面的例子,A,B两个用户同时登录,如果A先进入修改紧跟着B也进入了。A修改文档的同时B也在修改。如果在A保存之后B再保存他的修改,此时系统检测到数据库中文档记录与B刚进入时不一致,B保存时会抛出异常,修改失败。

乐观并发的基本出发点是:当保存数据的时候抱着一种乐观的态度,不期望发生并发冲突,即使万一发生并发冲突,也能捕捉到冲突异常,然后根据策略解决冲突,而解决冲突的方式一般分为Client wins(以后操作者为赢) 和 Store wins(以先存储的数据为赢)。

三、EF中如何控制并发

第1步、
  在设计器中,对需要进行并发控制的字段的ConcurrencyMode并发模式设置为Fixed,这是检测是否发生冲突的指标,该字段最终会在EF生成SQL时的where子句出现,如果没有设置为Fixed,即使该字段出现并发冲突,EF也不会报出并发异常,从而会导致出现脏读脏写的情况。
 
 
 
第2步、

 Resolving optimistic concurrency exceptions with Reload

  使用Reload数据作为解决乐观并发异常的策略之一,我在这里就讲数据Reload这一种策略就好了,除了Reload外,还有其他几种冲突解决策略,详见参考文献中EF官方团队博客。

  微软Entity Framework 团队官方博客 推荐处理乐观并发冲突的策略之一是Reload数据,也就是EF检测到并发冲突时会抛出DbUpdateConcurrencyException,这时解决冲突分为Client Wins或者Store Wins ,而Reload处理也就是Store Wins,意味着放弃当前内存中的实体,重新到数据库中加载当前实体,EF官方团队给出来的示例代码如下,其他几种策略请见参考文献链接。 
 
using (var context = new UnicornsContext())
{
bool saveFailed;
do
{
saveFailed = false;
var unicorn = context.Unicorns.Find();
unicorn.Name = "tom";
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;
// Update the values of the entity that failed to save
// from the store
ex.Entries.Single().Reload();
}
} while (saveFailed);
}

四、SqlProfiler看原理

  完成以上步骤后,您的程序就具备了乐观并发处理的能力了,但是,其中的原理是什么呢?从SqlProfiler监控结果来看,EF是将并发模式设置为Fixed的字段放在where子句里,后操作会因为取不到相应的记录而更新失败,打个比方说,当两个用户同时对同一条记录(ID=1,Count=10)进行读、写操作的时候,A、B同时读取记录的时候,Count都等于10,A用户先进行Update减1操作,此时(ID=1,Count=9),而此时B用户稍微晚一点点再进行Update操作的时候,因为Count已经被A修改成9了,已经不存在(ID=1,Count=10)的记录了,所以B最终执行影响行数为0,EntityFramework抛出并发异常:

如:我们给Count属性的并发模式设置成Fixed的话,那生成的SQL语句如下:


exec sp_executesql N'update [dbo].[OrderLog]
set [Count] = @
where (([ID] = @) and ([Count] = @2))',N'@ int,@ int,@ int',@0=78,@1=1,@2=9

当EntityFramework执行更新操如果影响行数为0,就会抛出异常,相关源代码如下所示:

 

五、总结

   个人认为,乐观并发控制适用于并发量还不是很大情况,也就是符合乐观并发的初衷,当保存数据的时候不期望发生并发冲突,一旦发生冲突,也能捕捉到冲突异常,然后根据策略解决冲突或者提示用户操作失败等,但是,当并发量很大的时候,我认为乐观并发就显得并不那么适用了,个人建议,做评估项目并发风险和做并发冲突的测试,假如完全可以接受,大可以应用EntityFramework的乐观并发控制,实现起来也比较简单,假如项目并发量确实很大,那可以考虑别的技术方案实现,比如消息队列……等。

 

参考文献

(1)微软EntityFramework团队博客: Using DbContext in EF 4.1 Part 9: Optimistic Concurrency Patterns

(2)Gyoung: Entity Framework 并发处理

Entity Framework 乐观并发控制的更多相关文章

  1. Entity Framework 乐观并发处理

    Entity Framework 乐观并发处理 有一段时间没有更新博客了,今天终于有一些时间,和大家讨论一个Entity Framework 乐观并发处理的问题.首先需要说明的是,这里提到的 “并发” ...

  2. C# Entity Framework并发处理

    原网站:C# Entity Framework并发处理 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NE ...

  3. C#综合揭秘——Entity Framework 并发处理详解

    引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的错误的一种机制.从 ADO.NET 到 LINQ to SQL 再到如今的 ADO.NET Entity Framework,.NET 都 ...

  4. [转]C#综合揭秘——Entity Framework 并发处理详解

    本文转自:http://www.cnblogs.com/leslies2/archive/2012/07/30/2608784.html 引言 在软件开发过程中,并发控制是确保及时纠正由并发操作导致的 ...

  5. Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制

    将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...

  6. Entity Framework Code First实现乐观并发

    Entity Framework Code First实现乐观并发 不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: h ...

  7. Entity Framework 6 Code First 系列:无需修改实体和配置-在MySql中使用和SqlServer一致的并发控制

    无需修改实体和配置,在MySql中使用和SqlServer一致的并发控制.修改RowVersion类型不可取,修改为Timestamp更不可行.Sql Server的RowVersion生成一串唯一的 ...

  8. Programming Entity Framework 翻译(1)-目录

    1. Introducing the ADO.NET Entity Framework ado.net entity framework 介绍 1 The Entity Relationship Mo ...

  9. Entity Framework 并发处理

    什么是并发? 并发分悲观并发和乐观并发. 悲观并发:比如有两个用户A,B,同时登录系统修改一个文档,如果A先进入修改,则系统会把该文档锁住,B就没办法打开了,只有等A修改完,完全退出的时候B才能进入修 ...

随机推荐

  1. ios 学习总结之动画(转)

    转自:http://blog.sina.com.cn/s/blog_a85effc301012wu4.html UIView的,翻转.旋转,偏移,翻页,缩放,取反的动画效果   翻转的动画 //开始动 ...

  2. 转载:PuTTY的自动登录设置

    转自:http://blog.segmentfault.com/zair/1190000000639516 PuTTY是Windows下非常好用的SSH远程登陆客户端.本文介绍两种自动登录的设置方法. ...

  3. POJ 1873 - The Fortified Forest 凸包 + 搜索 模板

    通过这道题发现了原来写凸包的一些不注意之处和一些错误..有些错误很要命.. 这题 N = 15 1 << 15 = 32768 直接枚举完全可行 卡在异常情况判断上很久,只有 顶点数 &g ...

  4. 开发板通过UART向主机发送数据

    /********************************* 代码功能:开发板通过UART向主机发送数据 使用函数: Serial.begin(数据传输的波特率); Serial.printl ...

  5. Collection List Set和Map用法与区别

    labels:Collection List Set和Map用法与区别 java 散列表 集合 Collection           接 口的接口      对 象的集合   ├   List   ...

  6. 【html/css】html/css命名规范

    无论做什么,规则总是最重要的.无规矩不成方圆,有了规矩,我们才能有规可循,有则可依,人与人之间才能正常的交流交往. 人人都有自己的命名习惯,不过,代码是需要交流的,当有些命名习惯仅只自己能看懂,甚至自 ...

  7. Errors occurred during the build. Errors running builder 'JavaScript Validator' on project 'XXX'.

    Errors occurred during the build. Errors running builder 'JavaScript Validator' on project 'XXX'.   ...

  8. 第五章 springboot + mybatis

    springboot集成了springJDBC与JPA,但是没有集成mybatis,所以想要使用mybatis就要自己去集成.集成方式相当简单. 1.项目结构 2.pom.xml <!-- 与数 ...

  9. Android(Xamarin)之旅(四)

    这么晚了,可能也因为一点事情,就说打开博客园看看,结果 http://www.cnblogs.com/mindwind/p/5125248.html 这篇文章瞬间吸引了我.暗暗的回想一下,十年之后,我 ...

  10. MVC过滤器

    MVC的每一个请求都会给相应的控制器的对应行为方法处理,那么想在这些处理的前 前后后增加一些额外的逻辑处理,因此过滤器的作用就来了 MVC支持的过滤器类型有四种,分别是:Authorization(授 ...