浅析Entity Framework Core中的并发处理

前言

Entity Framework Core 2.0更新也已经有一段时间了,园子里也有不少的文章..

本文主要是浅析一下Entity Framework Core的并发处理方式. 

1.常见的并发处理策略

要了解如何处理并发,就要知道并发的一般处理策略

悲观并发策略

悲观并发策略,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守悲观的态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观并发策略大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的巨大开销,特别是对长事务而言,这样的开销在大量的并发情况下往往无法承受。


乐观并发策略

乐观并发策略,一般是基于数据版本 Version记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现.读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。需要注意的是,乐观并发策略机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性.

本篇就是讲解,如何在我们的Entity Framework Core中来使用和自定义我们的并发策略 

2.Entity Framework Core并发令牌

要使用Entity Framework Core中的并发策略,就需要使用我们的并发令牌(ConcurrencyCheck)

在Entity Framework Core中,并发的默认处理方式是无视并发冲突的,任何修改语句在条件符合的情况下,都可以修改成功.

在高并发的情况下这种处理方式,肯定会给我们的数据库带来很多脏数据,所以,Entity Framework Core提供了并发令牌(ConcurrencyCheck)这个特性.

如果一个属性被配置为并发令牌,则EF将在保存这条记录时,会检查没有其他用户修改过数据库中的这个属性的值。EF使用了乐观并发策略,这意味着它将假定值没有改变,并尝试保存数据,但如果发现值已更改,则抛出异常。

举个例子,我们有一个用户类(User),我们配置 User中的 Name为并发令牌。这意味着,如果一个用户试图保存一个有些变化的 User,但另一个用户已经改变了 Name那么将抛出一个异常。这在应用中一般是可取的,以便我们的应用程序可以提示用户,在保存他们的改变之前,以确保此记录仍然代表同一个姓名的人。

2.1并发令牌在EF中工作的原理

当我们配置User中的Name为令牌的时候,EF会将并发令牌包含在Where、Update或delete命令子句中并检查受影响的行数来实现验证如果并发令牌仍然匹配,则一行将被更新。如果数据库中的值已更改,则不会更新任何行。

比如,当我们设置Name为并发令牌,然后通过ID来修改User的PassWord的时候,EF会生成如下的修改语句:

UPDATE [User] SET [PassWord] = @p1WHERE [ID] = @p0 AND [Name] = @p2;

当然,这时候,Name不匹配了,受影响的行数返回为0.

2.2并发令牌的使用约定

    属性默认不被配置为并发令牌。

 

2.3并发令牌的使用方式

1.直接使用特性,如下配置UserName为并发令牌:


public partial class UserTable
{       
     
public int Id { get; set; }[ConcurrencyCheck]    
    
public string UserName { get; set; }  

     
public string PassWord { get; set; }    

     
public int? ClassId { get; set; } }


 2.使用FluentAPI配置属性为并发令牌


class MyContext : DbContext
{ 
   
public DbSet<UserTable> People { get; set; }  
   
protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<UserTable>().Property(p => p.UserName).IsConcurrencyToken();} }


以上2种方式,效果是一样的.

 

2.4使用时间戳和行级版本号

我们知道,SQL Server给我们提供了时间戳的属性(当然,几乎所有的关系数据库都有这个).下面举个SQL Server的例子

我们加一个时间戳字段为TimestampV,加上特性Timestamp,实体代码如下:

  public partial class UserTable{      
        
public int Id { get; set; }      
        
public string UserName { get; set; }  
         
public string PassWord { get; set; }    
        
public int? ClassId { get; set; }  
         
public ClassTable Class { get; set; }[Timestamp]      
       
public byte[] TimestampV { get; set; }}


 

CodeFrist生成的表如下:

自动帮我们生成的Timestamp类型的一个字段.

配置时间戳属性的方式也有2种,上面已经说了一种..特性的..

同样我们也可以使用Fluent API配置属性为时间戳,代码如下:


class MyContext : DbContext
{   
 
public DbSet<UserTable> Blogs { get; set; }    
 
 protected
override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<UserTable>().Property(p => p.TimestampV).ValueGeneratedOnAddOrUpdate().IsConcurrencyToken();} }

3.如何根据需求自定义处理并发冲突

上面,我们已经配置好了需要并发处理的表,也配置好了相关的特性,下面我们就来讲讲如何使用它.

使用之前,我们先来了解一下,并发过程中所产生的3个值,也是我们需要处理的3个值

       1.当前值是应用程序尝试写入数据库的值。

       2.原始值是在进行任何编辑之前最初从数据库检索的值。

       3.数据库值是当前存储在数据库中的值。

当我们配置好上面的并发令牌时,在EF执行SaveChanges()操作并产生并发的时候,我们会得到DbUpdateConcurrencyException的异常信息,(注意:在不配置并发令牌时,这个异常一般不会触发)

前面,我们已经讲过乐观并发策略是一种性能较高,也比较实用的处理方式,所以我们就通过时间戳来处理这个并发的问题.

示例测试代码如下:

 public void Test(){            //重新创建数据库,并新增一条数据using (var context = new School_TestContext()){context.Database.EnsureDeleted();context.Database.EnsureCreated();context.UserTable.Add(new UserTable { UserName = "John", PassWord = "Doe" });context.SaveChanges();}            using (var context = new School_TestContext()){                // 修改id为1的用户名称var person = context.UserTable.Single(p => p.Id == 1);person.UserName = "555-555-5555";                // 直接通过访问数据库来修改同一条数据 (这里是为了模拟并发)context.Database.ExecuteSqlCommand("UPDATE dbo.UserTable SET UserName = 'Jane' WHERE ID = 1");          
               
try{                    //尝试保存修改int a = context.SaveChanges();}                //获取并发异常catch (DbUpdateConcurrencyException ex){                    foreach (var entry in ex.Entries){                
        
if (entry.Entity is UserTable){                    
        
var databaseEntity = context.UserTable.AsNoTracking().Single(p => p.Id == ((UserTable)entry.Entity).Id);                            var databaseEntry = context.Entry(databaseEntity);                            //当前上下文时间戳var date = ConvertToTimeSpanString(entry.Property("TimestampV").CurrentValue);                            var dateint = Int32.Parse(date, System.Globalization.NumberStyles.HexNumber);                            //数据库时间戳var datebase = ConvertToTimeSpanString(databaseEntry.Property("TimestampV").CurrentValue);                            var dateint2 = Int32.Parse(datebase, System.Globalization.NumberStyles.HexNumber);                            //如果当前上下文时间戳与数据库相同,或者更加新,则使用当前
if (dateint >= dateint2){                                foreach (var property in entry.Metadata.GetProperties()){                                    //当前值
var proposedValue = entry.Property(property.Name).CurrentValue;                                    //原始值
var originalValue = entry.Property(property.Name).OriginalValue;                                    //数据库值
var databaseValue = databaseEntry.Property(property.Name).CurrentValue;                                  
 
//更新当前值entry.Property(property.Name).CurrentValue = proposedValue;                                  
  
//更新原始值来保证修改成功entry.Property(property.Name).OriginalValue = databaseEntry.Property(property.Name).CurrentValue;                                    // 尝试重新保存数据int aa = context.SaveChanges();}}}                  
                      
else{                            throw new NotSupportedException("无法处理并发," + entry.Metadata.Name);}}}}}


执行这段代码,会发现,符合我们乐观并发策略的要求.

值为最后修改的UserName,为Jane,如图:

解释一下,为何最终结果为Jane.

首先,我们添加了一条UserName为John的数据,我们在上下文中修改它为"555-555-5555",

这时候,产生并发,另一个上下文在这个SaveChang之前,就执行完成了,把值修改为了Jane,所以EF通过并发令牌发现匹配失败.则会触发异常.

在异常中,我们将当前上下文的版本号和数据库现有的版本号进行对比,发现当前上下文的版本号为过期数据,则不更新,并返回失败.

请仔细看代码中的注释.

注意:这里的例子是根据乐观并发处理策略要进行处理的.你可以根据你的业务,来任意处理当前值,原始值和数据库值,选择你需要的值保存. 

写在最后

.net core已经2.0版本了,Asp.net Core也2.0了..EFcore也2.0了..功能已经越来越强大,越来越完善.完全可以投入生产了.园子里对这些新技术也很关注,真的...我感觉很棒..从未如此的棒!!!!

原文地址:http://www.cnblogs.com/GuZhenYin/p/7761352.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323077.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis的关联映射

学习目标 了解数据表之间以及对象之间的三种关联关系熟悉关联关系中的嵌套查询和嵌套结果掌握一对一、一对多和多对多关联映射的使用文章目录 1. 关联关系概述 2. 一对一 3.一对多 4. 多对多 1. 关联关系概述 一对一的关系&#xff1a;就是在本类中定义对方类型的对象一对…

【乱码】字符串乱码

1、html <meta charset"UTF-8">2、mysql mysql_query(set names "utf8");3、php header("Content-Type: application/json;charsetUTF-8");json解码 $a你好; echo json_encode($a);加入 $aurldecode($a);即可解码

.NET Core 使用RSA算法 加密/解密/签名/验证签名

前言 前不久移植了支付宝官方的SDK&#xff0c;以适用ASP.NET Core使用支付宝支付&#xff0c;但是最近有好几位用户反应在Linux下使用会出错&#xff0c;调试发现是RSA加密的错误&#xff0c;下面具体讲一讲。 RSA在.NET Core的改动 以前我们使用RSA加密主要是使用RSACryptoSe…

ajax读取.txt文件出现乱码

其实挺简单一问题&#xff0c;刚开始以为页面没输入 <meta charset"UTF-8">结果还是乱码&#xff0c;后来想到老师讲过&#xff0c;新建文件时保存文件有utf8和ANSI等格式&#xff0c;一看果然不对&#xff0c;自己每次新建文件默认格式都是ANSI&#xff0c;这…

萨提亚领衔主题演讲,带领高管和MVP合影,预告Julia女神的演讲中将有我的.NET Core实践

微软Tech Summit 2017大会在精彩的暖场视频中劲爆开始&#xff0c;瞬间点燃参会者们的热情。予力全球每一人、每一组织&#xff0c;成就不凡&#xff0c;是微软的使命。 微软公司首席执行官萨提亚 ∙ 纳德拉发布了主题演讲&#xff0c;他表示&#xff1a;“稳定发展、持续创新…

ajax读取文件未及时更新

在ajax读取文件&#xff08;.txt,.json&#xff09;时&#xff0c;会发生更改文件&#xff0c;ajax读取的还是原来的文件&#xff0c;要想改变这个可以在读取文件的后缀在加个&#xff1f;tXXX 具体情况如下 这样由于t值在变化&#xff0c;浏览器就会认为是个变化的值&#x…

基于.NET CORE微服务框架 -浅析如何使用surging

1、前言 surging受到大家这么强烈的关注&#xff0c;我感到非常意外&#xff0c;比如有同僚在公司的分享会上分享surging, 还有在博客拿其它的RPC框架&#xff0c;微服务做对比等等&#xff0c;这些举动都让我感觉压力很大&#xff0c;毕竟作为个人的开源项目&#xff0c;无法与…

2019年这50个Kafka面试题,你知道答案么

转载自 2019年这50个Kafka面试题&#xff0c;你知道答案么 Apache Kafka对于新手的面试问题&#xff1a;41, 42, 43, 44, 45, 47, 49 Apache Kafka对于有经验的人的面试问题&#xff1a;46, 48 Apache Kafka的受欢迎程度很高&#xff0c;Kafka拥有充足的就业机会和职业前景…

使用Visual Studio Code 开发.NET Core应用程序

开源和跨平台开发是Microsoft 的当前和将来至关重要的策略。.NET Core已开源&#xff0c;同时开发了其他项来使用和支持新的跨平台策略。.NET Core2.0 目前已经发布&#xff0c;是适用于针对 Web 和云构建跨平台应用程序的最新开源技术&#xff0c;可在 Linux、Mac OS X 和Wind…

Julia女神告诉我任何一家企业本质上都是一家软件公司

微软技术大会今天进入高潮&#xff0c;潘正磊女神发表题为“开发者在数字化转型中的关键价值”的主题演讲&#xff0c;积极评价开发者在各行业数字化转型中扮演的关键角色&#xff1b; 女神潘正磊表示&#xff1a;“由技术创新引领的数字化转型给全球各行业带来了巨大的变革和机…

P3391-[模板]文艺平衡树【Splay】

正题 题目连接:https://www.luogu.org/problemnew/show/P3391 题目大意 一个序列&#xff0c;m个操作翻转[l..r][l..r][l..r]区间。求最终序列 解题思路 节点维护编号&#xff0c;然后答案就是中序遍历。然后翻转的话我们先考虑一个性质。 若这是初始状态(l-1和r1反了) 然后…

Hadoop入门(三)HDFS API

一、、HDFS 常用类 Configuration 配置 Path 路径 FileSystem 文件系统 Stream 流 IOUtils IO工具 API文档 二、类解析 &#xff08;1&#xff09;Configuration 配置文件加载顺序 设置/获取参数方法 &#xff08;2&#xff09;Path Path 常用方法 &#xff08;3&…

在XUnit中用Moq怎样模拟EntityFramework Core下的DbSet

最近在做一个项目的单元测试时&#xff0c;遇到了些问题&#xff0c;解决后&#xff0c;觉得有必要记下来&#xff0c;并分享给需要的人&#xff0c;先简单说一下项目技术框架背景&#xff1a; asp.net core 2.0(for .net core)框架 用Entity Framework Core作ORM XUnit作单元…

解决idea中xml文件报红问题

报错截图&#xff1a; 解决方法&#xff1a; 复制爆红的约束链接file >>> settings >>> Languages & Frameworks >>> Schemas and DTDs右边框中找到 Ignored schemas and DTD3:点击加号添加约束&#xff0c;如下图应用即可&#xff01;

Hadoop入门(四)HDFS编程

一、编程环境设置 编程使用到idea2018&#xff0c;maven &#xff08;1&#xff09;启动集群 在window上启动vmware软件的虚拟机hadoop01&#xff0c;hadoop02&#xff0c;hadoop03。 进入hadoop01虚拟机启动集群&#xff0c;执行命令 start-dfs.sh &#xff08;2&#x…

ASP.NET Core 认证与授权[4]:JwtBearer认证

Bearer认证 HTTP提供了一套标准的身份验证框架&#xff1a;服务器可以用来针对客户端的请求发送质询(challenge)&#xff0c;客户端根据质询提供身份验证凭证。质询与应答的工作流程如下&#xff1a;服务器端向客户端返回401&#xff08;Unauthorized&#xff0c;未授权&#x…

隧道裂缝检测_2【C++PCL】

作者:迅卓科技 简介:本人从事过多项点云项目,并且负责的项目均已得到好评! 公众号:迅卓科技,一个可以让您可以学习点云的好地方 1.前言 我们团队注重每一个细节,确保代码的可读性、可维护性和可扩展性达到最高标准。我们严格遵循行业最佳实践,采用模块化和面向对象的设…

开源纯C#工控网关+组态软件(五)从网关到人机界面

一、 引子 之前都在讲网关&#xff0c;不少网友关注如何实现界面。想了解下位机变量变化&#xff0c;是怎样一步步触发人机界面动画的。 这个步步触发&#xff0c;实质上是变量组&#xff08;Group&#xff09;的批量数据变化&#xff08;DataChange&#xff09;事件&#xf…

P1315,jzoj3029-观光公交【费用流】

前言 你绝对想不到&#xff0c;我用费用流神仙构图做了一道 的题 正题 评测记录:https://www.luogu.org/recordnew/lists?uid52918&pidP1315 题目大意 有nnn个地方&#xff0c;iii到第i1i1i1的长度为did_idi​。 有mmm个人&#xff0c;从tit_iti​出发&#xff0c;从l…

Spring依赖注入和控制反转

文章目录1、依赖注入1.1、依赖注入和控制反转的概念1.2、依赖注入的实现方式1.3、控制反转的具体实现1.4、依赖注入的具体实现1.5、依赖注入和控制反转总结1、依赖注入 1.1、依赖注入和控制反转的概念 依赖注入(Dependency Injection, 简称DI)与控制反转(IoC)的含义相同&…