本文介绍如何处理多个用户并发更新同一实体(同时)时出现的冲突 。

主要是两种:一种,检查属性并发冲突,使用 [ConcurrencyCheck] ;另一种,检测行的并发冲突,使用 rowversion 跟踪属性,如果在保存之前有修改,就报错

发生并发冲突的情况:

  1.用户导航到实体编辑页面;

  2.第一个用户的更改还未写入数据库之前,另一个用户更新同一实体;

  此时,如果未启用并发检测,当发生更新时:

  最后一个更新优先。即最后一个更新的值保存到数据库。而第一个保存的值将丢失。

举个例子:

1. Jane 访问院系编辑页面,将英语系的预算从 350,000.00 美元更改为 0.00 美元 (第一个用户把金额改为0)

2.在 Jane 单击“保存”之前,John 访问了相同页面,并将开始日期字段从 2007/1/9 更改为 2013/1/9。 (在第一个用户保存之前,第二个用户把时间从07年改为13年,注意此时第二个用户看到的金额还不是0)

 3.Jane 先单击“保存”,并在浏览器显示索引页时看到她的更改。 (第一个用户先保存,并且可以在浏览器看到他的修改,金额变0,时间不变)

4.John 单击“编辑”页面上的“保存”,但页面的预算仍显示为 350,000.00 美元。 (第二个用户保存,此时的页面的预算显示未350000美元,时间为13年)

其实这个结果取决于并发冲突的处理方式

首先声明,这是一个乐观并发冲突,那么什么是乐观并发冲突呢?

乐观并发冲突允许发生并发冲突,并在并发冲突发生时作出正确的反映。

说了这么多,那么,并发冲突的处理方式呢?

1. 可以跟踪用户已修改的属性,并只更新数据库中相应的列。

这样,当两个用户更新了不同的属性,下次查看时,都将生效。

但是,这种方法,也有一些问题:

  • 当对同一个属性进行竞争性更改的话,无法避免数据丢失
  • 通常不适用于web应用。它需要维持重要状态,以便跟踪所有提取值和新值。 维持大量状态可能影响应
    用性能。
  • 可能会增加应用复杂性(与实体上的并发检测相比)。

体现在例子中,就是如果下次有人浏览英语系时,将看到 Jane 和 John
两个人的更改。

2.客户端优先

即客户端的值优先于数据库存储的值。并且如果不对并发处理进行任何编码,将自动进行客户端优先

即John 的更改覆盖 Jane 的更改 。也就是说,下次有人浏览英语系时,将看到 2013/9/1 和提取的值 350,000.00 美元

3.存储优先

这种方式可以阻止在数据库中John的更改。并且可以

  • 显示错误消息
  • 显示数据的当前状态
  • 允许用户重新应用更改。

处理并发

当属性配置为并发令牌时:

  • EF Core 验证提取属性后是否未更改属性。 调用 SaveChanges 或 SaveChangesAsync 时会执行此检查。
  • 如果提取属性后更改了属性,将引发 DbUpdateConcurrencyException。

数据库和数据模型必须配置为支持引发 DbUpdateConcurrencyException 。

检测属性的并发冲突

可使用 ConcurrencyCheck 特性在属性级别检测并发冲突。 该特性可应用于模型上的多个属性 。[ConcurrencyCheck] 特性

检测行的并冲突

要检测并发冲突,请将 rowversion 跟踪列添加到模型。

注意:rowversion , 

1.它是 SQL Server 特定的。 其他数据库可能无法提供类似功能。

2.用于确定从数据库提取实体后未更改实体。

数据库生成rowversion序号,该数字随着每次行的更新递增。

在 update 或 delete 命令中,where 子句中包括 rowversion提取值 的判断 。

如果要更新的行已经修改,则 rowversion提取值与现在数据库中rowversion的值不匹配;

update 或 delete 命令不能找到行。引发一个 DbUpdateConcurrencyException 异常

例子

向 Department 实体添加跟踪属性

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
{
public class Department
{
public int DepartmentID { get; set; }
[StringLength(, MinimumLength = )]
public string Name { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "money")]
public decimal Budget { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Start Date")]
public DateTime StartDate { get; set; }
public int? InstructorID { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; } //跟踪属性
public Instructor Administrator { get; set; }
public ICollection<Course> Courses { get; set; }
}
}

Timestamp 特性 指定此列包含在 update 和 delete 命令的 where 子句中。

也可以用 Fluent API 指定跟踪属性:

modelBuilder.Entity<Department>()
.Property<byte[]>("RowVersion")
.IsRowVersion();

以下代码显示更新 Department 名称时由 EF Core 生成的部分 T-SQL:

SET NOCOUNT ON;
UPDATE [Department] SET [Name] = @p0
WHERE [DepartmentID] = @p1 AND [RowVersion] = @p2;
SELECT [RowVersion]
FROM [Department]
WHERE @@ROWCOUNT = AND [DepartmentID] = @p1;

前面的代码显示包含 RowVersion 的 WHERE 子句。 如果数据库 RowVersion 不等于 RowVersion 参数( @p2
),则不更新行。

@@ROWCOUNT 返回受上一语句影响的行数。 在没有行更新的情况下,EF Core 引发
DbUpdateConcurrencyException

此文主要是为了方便自己记录学习,如有错误,欢迎指正

这里附上参考资料:

https://docs.microsoft.com/en-us/aspnet/core/data/ef-rp/concurrency?view=aspnetcore-2.2&tabs=visual-studio

 

 

asp.net core 系列之并发冲突的更多相关文章

  1. asp.net core系列 24 EF模型配置(主键,生成值,最大长度,并发标记)

    一.主键 键用作每个实体实例的主要唯一标识符. 使用关系数据库时,这会映射到主键的概念. 还可以配置不是主键的唯一标识符.按照约定,名为 Id 或 <type name>Id 的属性会配置 ...

  2. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  3. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  4. 1.1专题介绍「深入浅出ASP.NET Core系列」

    大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...

  5. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  6. asp.net core系列 40 Web 应用MVC 介绍与详细示例

    一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...

  7. asp.net core系列 39 Web 应用Razor 介绍与详细示例

    一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...

  8. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  9. asp.net core系列 36 WebAPI 搭建详细示例

    一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...

随机推荐

  1. 使用清华源替代Ubuntu源

    sudo nano /etc/apt/source.list 替换为如下文本 deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ xenial main ...

  2. python爬虫人门(10)Scrapy框架之Downloader Middlewares

    设置下载中间件(Downloader Middlewares) 下载中间件是处于引擎(crawler.engine)和下载器(crawler.engine.download())之间的一层组件,可以有 ...

  3. my views--软件工程、python

    这是大三第二学期开的一门课,由吴世枫老师和王韬助教教的. 大一开了C语言,大二开了java.matlab,而用得最多的应该是学java顺便学会的C++了.matlab在实训和数学建模用了多次,尤其是数 ...

  4. python字符串基本编码

    综述:python中字符串分为字节字符和非字节字符python3中默认输入字符串以非字节字符编码,使用unicode字符集表示,可以使用encode方法转化为ascii,utf-8, utf-16等各 ...

  5. Java NIO Scatter / Gather

    原文链接:http://tutorials.jenkov.com/java-nio/scatter-gather.html Java NIO发布时内置了对scatter / gather的支持.sca ...

  6. Java bean和json互转时,屏蔽某个属性

    有的时候我们把java bean 转换成json的时候,希望屏蔽掉某个属性,这时可以在java bean的属性上加上@JsonIgnore注解,在com.fasterxml.jackson.annot ...

  7. SSM-SpringMVC-05:SpringMVC视图解析器InternalResourceViewResolver配置

     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 视图解析器------默认就有配置,但是默认的在实际使用过程中有很多不方便的地方,所以我们配置一道视图解析器 ...

  8. python环境搭建-requests的简单安装(适合新手)

    安装完python之后,一定要记住安装后的路径.这是我当前的路径. 下面是requests的安装步骤: 我们这里直接用pip安装(这样比较适合新手),新版python自带pip,python3.6.1 ...

  9. Java开源生鲜电商平台-订单抽成模块的设计与架构(源码可下载)

    Java开源生鲜电商平台-订单抽成模块的设计与架构(源码可下载) 说明:订单抽成指的是向卖家收取相应的信息服务费.(目前市场上有两种抽成方式,一种是按照总额的抽成比率,另外一种是按照订单明细的抽成比率 ...

  10. Ueditor 专题

    https://github.com/xwjie/SpringBootUeditor 提交表单提交表单设置按照部署编辑器的教程,完成编辑器加载 把容器放到form表单里面,设置好要提交的路径,如下面代 ...