0. 并发冲突的示例

单用户的系统现在应该比较罕见了,一般系统都会有很多用户在同时进行操作;在多用户系统中,涉及到的一个普遍问题:当多个用户“同时”更新(修改或者删除)同一条记录时,该如何更新呢?
    下图展示了开放式并发冲突的一个示例:

假设数据库中有一条记录Record{Field1=5, Field2=6, Field3=7}(以下简写为{5, 6, 7}),A、B两个用户按照如下顺序操作这一条记录:
(1). A读取该记录,取得的值为{5, 6, 7},读取完毕后,不对该记录加排他锁;
(2). B读取该记录,取得的值也为{5, 6, 7},读取完毕后,不对该记录加排他锁;
(3). B将该记录修改为{3, 5, 7},并写回数据库;由于该记录没有被其他用户锁定,且B在修改时该记录的值与第(2)步中读取的值一致,因此可以正常写入数据库;
(4). A将该记录修改为{5, 8, 9},并写回数据库;由于A在修改时该记录的值已更新为{3, 5, 7},与第(1)步中读取的值{5, 6, 7}不一致,因此引发并发冲突;

1. 开放式并发(乐观并发) & 封闭式并发(悲观并发)

开始之前,先介绍两个概念(From 《SQL Server 2008联机丛书》)。

乐观并发控制

在乐观并发控制中,用户读取数据时不锁定数据。当一个用户更新数据时,系统将进行检查,查看该用户读取数据后其他用户是否又更改了该数据。如果其他用户更新了数据,将产生一个错误。一般情况下,收到错误信息的用户将回滚事务并重新开始。这种方法之所以称为乐观并发控制,是由于它主要在以下环境中使用:数据争用不大且偶尔回滚事务的成本低于读取数据时锁定数据的成本。

悲观并发控制

一个锁定系统,可以阻止用户以影响其他用户的方式修改数据。如果用户执行的操作导致应用了某个锁,只有这个锁的所有者释放该锁,其他用户才能执行与该锁冲突的操作。这种方法之所以称为悲观并发控制,是因为它主要用于数据争用激烈的环境中,以及发生并发冲突时用锁保护数据的成本低于回滚事务的成本的环境中。

举个例子来说:
    乐观并发:本文起始位置的图片,展示的是乐观并发情况下引发的冲突。
    悲观并发:继续沿用图片中示例的请求顺序,如果第(1)步中A读取这条记录后,给记录加上排他锁,并且一直持有,在更新完毕之前不释放该锁;则第(2)步中B尝试读取该记录时,请求会被阻塞,直到A释放该记录,或者请求超时。因此新的执行顺序(假设请求没有超时)为:A读取并锁定记录{5, 6, 7}-->B尝试读取该记录[B被阻塞等待]-->A写回{5, 8, 9}到数据库,并释放该记录-->B读取到{5, 8, 9},并锁定该记录-->B修改该记录并写回数据库……

2. Linq to SQL中的乐观并发控制

L2S支持开放式并发控制。使用L2S执行修改和删除操作时,同时打开SQL Server Profile来查看生成的SQL代码,我们可以看到类似这样的代码(假设表上加了TimeStamp字段):

UPDATE TableName SET Field1=@p0, Field2=@p1 WHERE PrimaryKey=@p2 AND TimeStampField=@p3

//(省略)....

DELETE TableName WHERE PrimaryKey=@p0 AND TimeStampField=@p1

//(省略)....

当记录被更新时,则其TimeStamp字段会被自动更新。因此,如果在用户读取该记录后、且更新该记录之前,有其他用户更新过这条记录,则更新会失败(根据受影响行数为0来判断),L2S会抛出ChangeConflictException异常。

以上描述的是表上有加timeStamp字段的情况,如果表上没有TimeStamp字段,L2S会对映射为UpdateCheck = UpdateCheck.Always 或 UpdateCheck.WhenChanged的字段成员进行开放式并发检查,可以根据Sql server Profile来查看,不再赘述。

3. 冲突解决

既然有了冲突,就需要把冲突给和谐掉。

还是以本文起始位置的例子来说,最后A更新时,该更新为啥呢?可以存在如下三种选择:
(1). 覆盖数据值库:{5,8,9}?
(2). 保留数据库值:{3,5,7}?
(3). 合并为:{3,8,9}?

这三种方式分别对了L2S的三种解决方案:

3.1 通过覆盖数据库值解决并发冲突

try

{

db.SubmitChanges(ConflictMode.ContinueOnConflict); //需要指定为ConflictMode.ContinueOnConflict

}

catch (ChangeConflictException e)

{

foreach (ObjectChangeConflict occ in db.ChangeConflicts)

{

occ.Resolve(RefreshMode.KeepCurrentValues); //保留当前值,覆盖数据库中的值

}

}

db.SubmitChanges(ConflictMode.FailOnFirstConflict); //处理完冲突后,重试

3.2 通过保留数据库值解决并发冲突

try

{

db.SubmitChanges(ConflictMode.ContinueOnConflict);

}

catch (ChangeConflictException e)

{

foreach (ObjectChangeConflict occ in db.ChangeConflicts)

{

occ.Resolve(RefreshMode.OverwriteCurrentValues);//以数据库中的值,重写当前值

}

}

db.SubmitChanges(ConflictMode.FailOnFirstConflict); //处理完冲突后,重试

3.3 通过与数据库值合并解决并发冲突

try

{

db.SubmitChanges(ConflictMode.ContinueOnConflict);

}

catch (ChangeConflictException e)

{

foreach (ObjectChangeConflict occ in db.ChangeConflicts)

{

occ.Resolve(RefreshMode.KeepChanges);//保留数据库中的值和当前值,进行合并处理

}

}

db.SubmitChanges(ConflictMode.FailOnFirstConflict); //处理完冲突后,重试

Linq to Sql并发冲突及处理策略的更多相关文章

  1. Linq to Sql : 并发冲突及处理策略

    原文:Linq to Sql : 并发冲突及处理策略 1. 通过覆盖数据库值解决并发冲突 try { db.SubmitChanges(ConflictMode.ContinueOnConflict) ...

  2. Linq to sql并发与事务

    本文转载:http://www.cnblogs.com/lovecherry/archive/2007/08/20/862365.html 检测并发 首先使用下面的SQL语句查询数据库的产品表: se ...

  3. [Linq To Sql]解决join时的Collation冲突

    背景 现在两表 A:

  4. LINQ to SQL大全

    LINQ to SQL语句 (1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的 ...

  5. [转]LINQ To SQL 语法及实例大全

    转载自:http://blog.csdn.net/pan_junbiao/article/details/7015633 LINQ to SQL语句(1)之Where Where操作 适用场景:实现过 ...

  6. LINQ to SQL语句非常详细(原文来自于网络)

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...

  7. LINQ To SQL 语法及实例大全

    http://blog.csdn.net/pan_junbiao/article/details/7015633 http://blog.csdn.net/pan_junbiao/article/de ...

  8. 转载linq to sql 的详解

    [转]LINQ To SQL 语法及实例大全 2011-11-26阅读38651 评论9 LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL ...

  9. Linq to sql语法

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...

随机推荐

  1. 数据包编辑工具bittwiste

    数据包编辑工具bittwiste   bittwiste是数据包重放工具bittwist的一个工具.该工具可以编辑修改PCAP抓包文件.该工具提供数据包过滤功能,如根据范围和时间过滤.同时,该工具支持 ...

  2. C# asp.net 抓取需要登录的网页内容 抓取asp.net登录验证的网站

    private void btnASPNET_Click(object sender, EventArgs e)        {            Dictionary<string, s ...

  3. 用C语言的rand()和srand()产生伪随机数的方法总结

    标准库<cstdlib>(被包含于<iostream>中)提供两个帮助生成伪随机数的函数: 函数一:int rand(void):从srand (seed)中指定的seed开始 ...

  4. JDBC之 大数据内容的传输

    JDBC之 大数据内容的传输 什么是大数据内容? 在数据库中,有一条一条的记录,记录中很多字段都是几个字符就够的,假如现在要把一部小说存入数据库,这本小说当然不是几个字符组成,而是由几万字组成,这本小 ...

  5. SQL语句之 数据约束

    SQL语句之 数据约束 什么是数据约束 数据约束用来限制用户对数据的非法的修改操作. 1.约束字段的默认值 如果插入记录时,没有给某个字段赋值,那么我们可以设置它的默认值 关键字:default CR ...

  6. 【转】NHibernate对象以及状态说明

    对象 ISessionFactory (NHibernate.ISessionFactory) 针对单个数据库映射关系经过编译后的内存镜像,是线程安全的(不可变). 它是生成ISession的工厂,本 ...

  7. 微服务架构的分布式事务解决方案 - zhaorui2017的博客 - CSDN博客

    微服务架构的分布式事务解决方案 - zhaorui2017的博客 - CSDN博客   http://blog.csdn.net/zhaorui2017/article/details/7643679 ...

  8. Canbus ID filter and mask

    Canbus ID filter and mask CANBUS is a two-wire, half-duplex, bus based LAN system that is ‘collision ...

  9. ubuntu单独安装字体包

    查看当前字体的命令: fc-list 文泉驿字体下载地址: http://wenq.org/wqy2/index.cgi?ZenHei#v0_8 下载到的是一个deb安装包 在下载完字体以后将字体包拷 ...

  10. 基于设备树的controller学习(1)

    作者 彭东林pengdonglin137@163.com 平台 TQ2440Linux-4.10.17 概述 在设备树中我们经常见到诸如"#clock-cells"."# ...