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. linux驱动之LCD(无framebuffer)

    <简介> a:什么是液晶 物质一般有三态,固态,气态,和液态.这只是一种比较大致的划分,但是有些物质介于液体和固体之间——液晶.一般固体的分子或原子都由固定的排列方式,但是液晶介于固体和液 ...

  2. Loj 10211 sumdiv

    题目描述 求 A^B 的所有约数之和 mod 9901. 首先,我们要求出A的约数之和. 就是把A分解质因数,成为:a1^k1*a2^k2*a3^k2.... 然后约数和就是(a1^0+a1^1+a1 ...

  3. 吴恩达-coursera-机器学习-week9

    十五.异常检测(Anomaly Detection) 15.1 问题的动机 15.2 高斯分布 15.3 算法 15.4 开发和评价一个异常检测系统 15.5 异常检测与监督学习对比 15.6 选择特 ...

  4. 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem C. Equivalent Cards 计算几何

    Problem C. Equivalent Cards 题目连接: http://www.codeforces.com/gym/100253 Description Jane is playing a ...

  5. hdu 5781 ATM Mechine dp

    ATM Mechine 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5781 Description Alice is going to take ...

  6. CentOS 7解压安装PHP7.1.21

    下载php yum install -y wget wget http://cn2.php.net/distributions/php-7.1.21.tar.gz 解压 tar -zxvf php-7 ...

  7. UVA 12436 - Rip Van Winkle&#39;s Code(线段树)

    UVA 12436 - Rip Van Winkle's Code option=com_onlinejudge&Itemid=8&page=show_problem&cate ...

  8. intel32指令中文版

    http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User's%20Guide/mergedProjects/analyzer_ec/mer ...

  9. solaris 软件包地址

      1. http://www.opencsw.org/ 在Solaris 10下 1.安装pkgutil pkgadd -d http://get.opencsw.org/now 2.查询有那些PK ...

  10. STL中经常使用数据结构

    STL中经常使用的数据结构: [1]  stack.queue默认的底层实现为deque结构. [2]  deque:用map管理多个size大小的连续内存块,方便头尾插入. [3]  vector: ...