并发处理实战

2019-10-29 06:47 来源:未知

4.4 当爆发多少现身时,保留最先(最早:最初叁回)输入的数目

把指标属性的 ConcurencyMode 设置为 Fixed 后,同有的时候间更新该属性,将会激起OptimisticConcurrencyException 格外。当时利用 ObjectContext.Refresh (RefreshMode,object) 刷新上下文中该目的的情景,当 RefreshMode 为 StoreWins 时,系统就可以把数据源中的数据代表上下文中的数额。
因为初次调用 SaveChanges,数据足以成功保存到数据库。不过在 ObjectContext 并未有释放时,再度行使 SaveChanges 异步更新数据,就能够抓住OptimisticConcurrencyException 并发十分。当 RefreshMode 为 StoreWins 时,系统就能够保留初次输入的数据属性。
此例子与地点的例证十分雷同,只是把 RefreshMode 改为 StoreWins 而已。在工作逻辑较为复杂的的种类此中,提出利用此措施管理并发极度。在保留最早输入的数目校正属性后,把属性返还给顾客,让顾客进行相比后再决定下一步的管理格局。

图片 1

图片 2

 

考查测量检验结果,可以见到当 RefreshMode 状态为 StoreWins 时,系统将会以数据源中的数据代表上下文在那之中的靶子属性。在业务逻辑较为复杂的的体系个中,提出使用此方法处理并发格外。


链接: 密码: fyb3

演练的源码,有改革的大错特错的对象记得共享

学习:C#归根到底揭秘——Entity Framework 并发管理详解 帖子笔记 ,该帖子使用的是objectContext ,

四、乐观并发

为了消除悲观并发所推动的题目,ADO.NET Entity Framework 提供了特别便捷的开朗并发管理情势。相对于LINT to SQL , ADO.NET Entity Framework 简化了有超级大希望并发的管理方式,它能够灵活使用合併数据、保留初次输入数据、保留最新输入数据(3种方式)等艺术处理并发冲突。

4.1 剔除与更新操作同一时间运营(非框架自动处理手艺,开辟电动修正意况手动扩大的)**

Entity Framework 能以完备的建制灵活管理同不平日候更新同生龙活虎对象的操作,但如若删除操作与更新操作同不时候运行时,就大概存在逻辑性的相当。

比方:四个顾客端同时加载了同贰个对象,第三个客商端更新了数额后,把多少再次提交。但在付给前,第二个客商端已经把数据库中的本来就有数量删除。

那时,上下文中的对象处于分裂的图景下,将会掀起 OptimisticConcurrencyException 非凡(ObjectContext 与DBContext两种情势下,万分不相像,具体要遵照测量试验结果本人看清)。
遇见此特别时,能够用 try(OptimisticConcurrencyException){...} catch {...} 情势抽薪止沸分外,然后改造对象的State 属性。把EntityState 改良为 Added ,被删去的数额便会被重复加载。若把 EntityState 修改为 Detached 时,数据便会被顺遂删除。上面把指标的 EntityState 属性改正为 Added 作为例子。

图片 3

代码如下:管理结果前后ID变化了(只怕那正是有个别架构师使用手动创造的GUID的方法,而不接纳自增的缘故之生龙活虎吧,因为数量删除后再次创下设就回不到在此以前的ID了,不是太灵活,使用GUID再组成数据版本(dataVison)字段,timeStamp基本上调节数据的面世已经充足啊。

//更新对象
        public int UpdateWithConcurrent(int num, Address addressValue)
        {
            int returnValue = -1;
            using (OrderDBContainer context = new OrderDBContainer())
            {
                var obj = context.AddressSet.Where(x => x.Id == addressValue.Id).First();
                //显示对象所处状态
                DisplayState("Before Update", obj);
                try
                {
                    if (obj != null)
                        context.Entry(obj).CurrentValues.SetValues(addressValue);
                    //虚拟操作,保证数据已经在数据库中被异步删除
                    Thread.Sleep(300);
                    context.SaveChanges();
                    returnValue = obj.Id;
                }
                catch (Exception)
                {
                    //针对异常要做相应的判断,因为我只测试了删除的情况,就写死直接修改成Added 了
                    //正确的是要区分到底是修改还是删除  OptimisticConcurrencyException ex
                    //把对象的状态更改为 Added
                    context.Entry(obj).State = System.Data.Entity.EntityState.Added;
                    context.SaveChanges();
                    returnValue = obj.Id;
                }
            }
            return returnValue;
        }

并发时的百般类型:

图片 4

ID产生了变动

图片 5

 

二、模型属性的面世管理选项

如下图模型设计器中TimeStamp字段为启用并发

图片 6

<EntityType Name="UserAccout">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
          <Property Name="FirstName" Type="String" Nullable="false" />
          <Property Name="LastName" Type="String" Nullable="false" />
          <Property Name="AuditFileds" Type="OrderDB.AuditFields" Nullable="false" />
          <Property Name="Timestamp" Type="DateTime" Nullable="false" ConcurrencyMode="Fixed" annotation:StoreGeneratedPattern="Computed" />
        </EntityType>

现身格局:ConcurencyMode 有七个分子:

None : 在写入时不曾验证此属性。 这是暗许的现身形式。

Fixed: 在写入时平昔验证此属性。

当模型属性为暗中同意值 None 时,系统不会对此模型属性进行检查测验,当同三个岁月对此属性进行更改时,系统会以数据统一情势管理输入的属性值。

当模型属性为Fixed 时,系统会对此模型属性进行检测,当同三个时刻对品质进行更正时,系统就能激情OptimisticConcurrencyException 非凡。

 

大器晚成、并发相关概念

现身的品类:

率先种方式称为悲观式并发,即当二个客户已经在改变某条记下时,系统将不容其余顾客同临时候改进此记录。
其次种情势称为乐观式并发,即系统允许八个顾客同一时候改正同一条记下,系统会预先定义由数据现身所引起的产出十分管理情势,去管理改进后或许爆发的冲突。常用的乐观性并发管理办法有以下三种:

    1、保留最终改革的值。
    2、保留最早改善的值。
    3、合併往往修正的值。

4.1 以联合方式管理并发数据

小结:当模型属性的 ConcurencyMode 为私下认可值 None ,生机勃勃旦同一个指标属性同一时间被改过,系统将以统意气风发数据的格局管理并发冲突,那也是 Entity Framework 管理并发冲突的私下认可格局。

会集管理方式如下:

(1)当同不时候针对同一个对象属性作出修改,系统将保存最新输入的属性值。

(2)当同时对相符对象的两样性质作出改良,系统将保留已被涂改的属性值。上边用三个例子作出表达:

图片 7

运作结果:

图片 8

#region (4.1)测试不设置任何并发测试时,当产生并发EF的处理方法
        delegate void MyDelegate(Address addressValue);
        public  StringBuilder sb = new StringBuilder();
        public Address GetAddress(int id)
        {
            using (OrderDBContainer context = new OrderDBContainer())
            {
                IQueryable<Address> list = context.AddressSet.Where(x => x.Id == id);
                return list.First();
            }
        }
        /// <summary>
        /// 修改方法
        /// </summary>
        /// <param name="addressValue"></param>
        public void UpdateAddress(Address addressValue)
        {
            using (OrderDBContainer context = new OrderDBContainer())
            {
                //显示输入新数据的信息
                Display("Current", addressValue);
                var obj = context.AddressSet.Where(x => x.Id == addressValue.Id).First();
                if (obj != null)
                    context.Entry(obj).CurrentValues.SetValues(addressValue);
                //虚拟操作,保证数据能同时加入到上下文当中
                Thread.Sleep(100);
                context.SaveChanges();
            }
        }        
        /// <summary>
        /// 显示实体当前属性
        /// </summary>
        /// <param name="message"></param>
        /// <param name="addressValue"></param>
        public void Display(string message, Address addressValue)
        {
            String data = string.Format("{0}n  Address Message:n    Id:{1}  Address1:{2}  " +
                "address2:{3} rn ",
                message, addressValue.Id, addressValue.Address1, addressValue.Address2 );
            sb.AppendLine(data);
        }     

        /// <summary>
        /// (1)测试使用EF默认的机制,当配置并发控制时,系统是使用的合并的方式
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            //在更新数据前显示对象信息
            var beforeObj = GetAddress(1);
            Display("Before", beforeObj);

            //更新Person的SecondName,Age两个属性
            Address _address1 = new Address();
            _address1.Id = 1;
            _address1.Address1 = "古溪";
            _address1.Address2 = beforeObj.Address2;
            _address1.AuditFields.InsertDate = beforeObj.AuditFields.InsertDate;
            _address1.AuditFields.UpdateDate = beforeObj.AuditFields.UpdateDate;
            _address1.City = beforeObj.City;
            _address1.Zip = beforeObj.Zip;
            _address1.State = beforeObj.State;

            //更新Person的FirstName属性
            Address _address2 = new Address();
            _address2.Id = 1;
            _address2.Address1 = beforeObj.Address1;
            _address2.Address2 = "江苏";
            _address2.AuditFields.InsertDate = beforeObj.AuditFields.InsertDate;
            _address2.AuditFields.UpdateDate = beforeObj.AuditFields.UpdateDate;
            _address2.City = beforeObj.City;
            _address2.Zip = beforeObj.Zip;
            _address2.State = beforeObj.State;

            //使用异步方式同时更新数据
            MyDelegate myDelegate = new MyDelegate(UpdateAddress);
            myDelegate.BeginInvoke(_address1, null, null);
            myDelegate.BeginInvoke(_address2, null, null);

            Thread.Sleep(1000);
            //在更新数据后显示对象信息
            var afterObj = GetAddress(1);
            Display("After", afterObj);
            this.textBox1.Text = sb.ToString();
        }

        /// <summary>
        /// 先插入几条数据等着测试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnSaveAddress_Click(object sender, EventArgs e)
        {
            using (OrderDBContainer db = new OrderDBContainer())
            {
                Address address = new Address();
                address.Address1 = "古溪镇";
                address.Address2 = "安镇";
                address.State = "2";
                address.City = "无锡";
                address.AuditFields.InsertDate = DateTime.Now;
                address.AuditFields.UpdateDate = DateTime.Now;
                address.Zip = "21415";
                db.AddressSet.Add(address);
                db.SaveChanges();
            }
        }

        /// <summary>
        /// 还原成初始值,准备再次测试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            using (OrderDBContainer db = new OrderDBContainer())
            {
                Address _address = db.AddressSet.Where(x => x.Id == 1).First();
                _address.Address1 = "aaa";
                _address.Address2 = "bbb";
                db.SaveChanges();
            }
        }
        #endregion

备注:实行进度中遇见的难点

在多线程中EF改善事件的缓和方案,使用attach不得以:

图片 9

使用Entry也报错

图片 10

最后参照他事他说加以考查如下帖子

图片 11

/// <summary>
        /// 修改方法
        /// </summary>
        /// <param name="addressValue"></param>
        public void UpdateAddress(Address addressValue)
        {
            using (OrderDBContainer context = new OrderDBContainer())
            {
                //显示输入新数据的信息
                Display("Current", addressValue);
                var obj = context.AddressSet.Where(x => x.Id == addressValue.Id).First();
                if (obj != null)
                    context.Entry(obj).CurrentValues.SetValues(addressValue);
                //虚拟操作,保证数据能同时加入到上下文当中
                Thread.Sleep(100);
                context.SaveChanges();
            }
        }

引用:“以统风流倜傥数据的章程管理并发冲突纵然方便快节,但在职业逻辑较为复杂的系统下并不契合采用此管理方式。比方在科学普及的Order、OrderItem的表格中,OrderItem 的单价,数量会一贯影响Order的豆蔻梢头体化价格,那样使用合併数据的方法管理并发,有超级大概率引起逻辑性的失实。当时,应该考虑以此外措施管理并发冲突。”。

此外什么方式啊?【待补充】

 

4.3 当发生多少现身时,保留最后(最新:最后三次)输入的多少

要证实输入对象的属性,必需先把该属性的 ConcurencyMode 设置为 Fixed,那样系统就能够实时检查评定对象属性的输入值 。
当该属性被同期更新,系统便会慰勉 OptimisticConcurrencyException 万分。捕获该非常后,能够接纳 ObjectContext.Refresh (RefreshMode,object) 刷新上下文中该对象的情状,当 RefreshMode 为 ClientWins 时,系统将会维持内外文中的前几天有多少,即保留最新输入的靶子值。这个时候再采纳ObjectContext.SaveChanges, 系统就能够把新型输入的目的值参预数据库个中。

在底下的例子当,系统运行前先把 Person 的 FirstName、SecondName 八个天性的 ConcurencyMode 属性设置为Fixed,使系统能监视那多个属性的校订。所输入的数据只在FirstName、SecondName 八个值中作出修正。在数据交由前先以 DisplayProperty 方法展现数据库最早的数目属性,在数量初次更新后再一次调用 DisplayProperty 展现更新后的数码属性。在其次次改正数据时,由调用ObjectContext.SaveChanges时,数据库中的数据现已被修改,与方今上下文ObjectContext 的多寡存在冲突,系统将鼓舞OptimisticConcurrencyException 万分,那个时候把吸引那么些的靶子属性再度展现出来。对格外进行拍卖后,显示数据库中最后的靶子值。

 

 

观测测验结果,可以预知当RefreshMode状态为ClientWins时,系统将会保留上下文当中的靶子属性,使用此格局可以在发生并发分外时保持最新输入的目的属性。

 

三、悲观并发

 

TAG标签:
版权声明:本文由银河国际点击登录发布于手机客户端,转载请注明出处:并发处理实战