• asp.net core 系列之并发冲突


    本文介如何理多个用更新同一体(同的冲突 。

    主要是两种:一种,检查属性并发冲突,使用 [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(50, MinimumLength = 3)]
    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
    = 1 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







     

     

  • 相关阅读:
    worker与redis网络中断后,worker不再接受任务的异常问题
    Pyecharts 绘制动态流线地图
    MySql存储过程知识了解
    Pyecharts配置项使用
    Pandas一个需求:存在一个列表,需要在一个DataFrame中取到以该列表为索引的数据
    mysql时间与字符串之间相互转换
    map + apply + applymap
    pandas——read_csv
    Python 原生协程------asyncio(选自公众号)
    一道记数题
  • 原文地址:https://www.cnblogs.com/Vincent-yuan/p/10765989.html
Copyright © 2020-2023  润新知