Linq to sql:检测并发
来源:互联网 发布:淘宝不能上传新图片 编辑:程序博客网 时间:2024/05/30 02:52
首先使用下面的SQL语句查询数据库的产品表:
select *from products wherecategoryid=1
为了看起来清晰,我已经事先把所有分类为1产品的价格和库存修改为相同值了。然
后执行下面的程序:
var query =from p in ctx.Products where p.CategoryID == 1select p;
foreach (var pinquery)
p.UnitsInStock =Convert.ToInt16(p.UnitsInStock - 1);
ctx.SubmitChanges(); // 在这里设断点
我们使用调试方式启动,由于设置了断点,程序并没有进行更新操作。此时,我们在数
据库中运行下面的语句:
update products
set unitsinstock= unitsinstock-2, unitprice= unitprice+ 1
where categoryid= 1
然后在继续程序,会得到修改并发(乐观并发冲突)的异常,提示要修改的行不存在或
者已经被改动。当客户端提交的修改对象自读取之后已经在数据库中发生改动,就产生了修
改并发。解决并发的包括两步,一是查明哪些对象发生并发,二是解决并发。如果你仅仅是
希望更新时不考虑并发的话可以关闭相关列的更新验证,这样在这些列上发生并发就不会出
现异常:
[Column(Storage="_UnitsInStock", DbType="SmallInt", UpdateCheck =
UpdateCheck.Never)]
[Column(Storage="_UnitPrice", DbType="Money", UpdateCheck = UpdateCheck.Never)]
为这两列标注不需要进行更新检测。假设现在产品价格和库存分别是27和32。那么,
我们启动程序(设置端点),然后运行UPDATE语句,把价格+1,库存-2,然后价格和库
存分别为28和30 了,继续程序可以发现价格和库存分别是28和31。价格+1是之前更新
的功劳,库存最终是-1是我们程序之后更新的功劳。当在同一个字段上(库存)发生并发
冲突的时候,默认是最后的那次更新获胜。
解决并发
如果你希望自己处理并发的话可以把前面对列的定义修改先改回来,看下面的例子:
var query =from p in ctx.Products where p.CategoryID == 1select p;
foreach (var pinquery)
p.UnitsInStock =Convert.ToInt16(p.UnitsInStock - 1);
try
{
ctx.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException)
{
foreach (ObjectChangeConflict ccinctx.ChangeConflicts)
{
Product p = (Product)cc.Object;
Response.Write(p.ProductID +"<br/>");
cc.Resolve(RefreshMode.OverwriteCurrentValues);// 放弃当前更新,
所有更新以原先更新为准
}
}
ctx.SubmitChanges();
首先可以看到,我们使用try{}catch{}来捕捉并发冲突的异常。在SubmitChanges的时
候,我们选择了ConflictMode.ContinueOnConflict选项。也就是说遇到并发了还是继续。
在catch{}中,我们从ChangeConflicts中获取了并发的对象,然后经过类型转化后输出了
产品ID,然后选择的解决方案是RefreshMode.OverwriteCurrentValues。也就是说,放弃
当前的更新,所有更新以原先更新为准。
我们来测试一下,假设现在产品价格和库存分别是27和32。那么,我们启动程序(在
ctx.SubmitChanges(ConflictMode.ContinueOnConflict)这里设置端点),然后运行UPDATE
语句,把价格+1,库存-2,然后价格和库存分别为28和30 了,继续程序可以发现价格和
库存分别是28和30。之前SQL语句库存-2 生效了,而我们程序的更新(库存-1)被放弃
了。在页面上也显示了所有分类为1的产品ID(因为我们之前的SQL语句是对所有分类为
1 的产品都进行修改的)。
然后,我们来修改一下解决并发的方式:
cc.Resolve(RefreshMode.KeepCurrentValues);// 放弃原先更新,所有更新以当前更新为
准
来测试一下,假设现在产品价格和库存分别是27和32。那么,我们启动程序(在
ctx.SubmitChanges(ConflictMode.ContinueOnConflict)这里设置端点),然后运行UPDATE
语句,把价格+1,库存-2,然后价格和库存分别为28和30 了,继续程序可以发现价格和
库存分别是27和31。产品价格没有变化,库存-1了,都是我们程序的功劳,SQL语句的
更新被放弃了。
然后,我们再来修改一下解决并发的方式:
cc.Resolve(RefreshMode.KeepChanges);// 原先更新有效,冲突字段以当前更新为准
来测试一下,假设现在产品价格和库存分别是27和32。那么,我们启动程序(在
ctx.SubmitChanges(ConflictMode.ContinueOnConflict)这里设置端点),然后运行UPDATE
语句,把价格+1,库存-2,然后价格和库存分别为28和30 了,继续程序可以发现价格和
库存分别是28和31。这就是默认方式,在保持原先更新的基础上,对于发生冲突的字段以
最后更新为准。
我们甚至还可以针对不同的字段进行不同的处理策略:
foreach (ObjectChangeConflict ccinctx.ChangeConflicts)
{
Product p = (Product)cc.Object;
foreach (MemberChangeConflict mcincc.MemberConflicts)
{
string currVal = mc.CurrentValue.ToString();
string origVal = mc.OriginalValue.ToString();
string databaseVal = mc.DatabaseValue.ToString();
MemberInfo mi = mc.Member;
string memberName = mi.Name;
Response.Write(p.ProductID + " " + mi.Name + " " + currVal + " " + origVal +" "+
databaseVal + "<br/>");
if (memberName =="UnitsInStock")
mc.Resolve(RefreshMode.KeepCurrentValues);// 放弃原先更新,所有更新
以当前更新为准
else if (memberName =="UnitPrice")
mc.Resolve(RefreshMode.OverwriteCurrentValues);// 放弃当前更新,所有
更新以原先更新为准
else
mc.Resolve(RefreshMode.KeepChanges);// 原先更新有效,冲突字段以当
前更新为准
}
}
比如上述代码就对库存字段作放弃原先更新处理,对价格字段作放弃当前更新处理。我
们来测试一下,假设现在产品价格和库存分别是27和32。那么,我们启动程序(在
ctx.SubmitChanges(ConflictMode.ContinueOnConflict)这里设置端点),然后运行UPDATE
语句,把价格+1,库存-2,然后价格和库存分别为28和30 了,继续程序可以发现价格和
库存分别为28和31 了。说明对价格的处理确实保留了原先的更新,对库存的处理保留了
当前的更新。页面上显示的结果如下图:
最后,我们把提交语句修改为:
ctx.SubmitChanges(ConflictMode.FailOnFirstConflict);
表示第一次发生冲突的时候就不再继续了,然后并且去除最后的ctx.SubmitChanges();
语句。来测试一下,在执行了SQL后再继续程序可以发现界面上只输出了数字1,说明在
第一条记录失败后,后续的并发冲突就不再处理了。
- Linq to sql:检测并发
- 并发概述(LINQ to SQL)
- LinQ to SQL 并发与事务
- Linq 并发检测
- 在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测
- linq,linq to sql
- 一步一步学Linq to sql(七):并发与事务
- 一步一步学Linq to sql(七):并发与事务
- 一步一步学Linq to sql(七):并发与事务
- Linq to Sql 学习系列之七 并发与事务
- Linq to Sql : 并发冲突及处理策略
- 一步一步学Linq to sql(七):并发与事务
- 一步一步学Linq to sql(七):并发与事务
- 一步一步学Linq to sql(七):并发与事务
- Linq to Sql(七):并发与事务
- DLINQ(LINQ to SQL)之事务处理和并发处理
- 一步一步学Linq to sql(七):并发与事务
- DLINQ(LINQ to SQL)之事务处理和并发处理
- Linq to sql: DataContext 隔离
- Shell脚本中的并发(2)
- iOS效率提升工具
- linux 安装zip和压缩解压文件
- 未能解决bug之java.io.IOException: Not in GZIP format
- Linq to sql:检测并发
- thrift安装
- poj 3680 Intervals
- Perl内置特殊变量
- Html5 学习系列(三)增强型表单标签
- 使用hash表加速寻找-POJ 3349
- js中setAttribute 的兼容性
- "Cannot declare member function ...to have static linkage"错误
- Mahout0.6-VectorDumper bug修复