一、(引言)
小菜通过一个简单的例子来说明如何进行并发处理,大家不用当心例子太简单反映不了问题。
小菜通过运行两个实例来模拟两个客户端。
一个阿猫、阿狗引发的故事:
数据库中记录:
客户端1:加载
客户端2:加载
客户端1在本地具有一份数据副本,名字暂时称为 副本1
客户端2在本地也具有一份数据副本,名字暂时称为 副本2
客户端1修改记录:AnimalID = 1 and AnimalType = "狗" 修改成 AnimalID = 1 and AnimalType = "阿狗"
修改的只是副本1中的数据,点击保存,将修改更新到服务器。
客户端1:
数据库中记录:
看来数据更改成功。
客户端2:
从图可以看出:客户端2并不知道客户端1已经把 AnimalType = "狗" 修改成了 AnimalType = "阿狗"
这时如果客户端2将 AnimalID = 1 and AnimalType = “狗”修改成了 AnimalID = 1 and AnimalType = “阿黄”
怎么办呢?(小菜也不知道怎么办,因为我们不知道用户想干什么)
用户目的是:将“狗”改成“阿黄”
如果用户知道了别人已经将“狗”改成了“阿狗”
用户可能会继续更改,也可能放弃更改。(这就出现了两种可能!!!)
所以我们应该让用户自己来选择:
以上解决并发处理的方案称为:开放式并发处理.
对应的保守式并发处理:
是当用户编辑数据库中的某行数据时,保守式并发会使此数据一直保持锁定.在锁定期间,其他用户不能更改数据,这样能够最高程度的保证数据的完整性,但是可用性低.
代码下载:https://files.cnblogs.com/a-peng/SmartClient_Chapter05.rar
(二)、分析
1、使用TableAdapter + 类型化DataSet 完成开放式并发处理
演化一:
新建Web服务:Server
添加数据集:DataSetAnimals(配置略,注意使用开放式并发 和 刷新数据表两个选项)
添加Web服务:DataService.asmx
代码如下:
添加Web服务引用,名称:DataWS
添加窗体:MainForm
代码如下:
左边为客户端1,右边为客户端2。
客户端1将狗,猫,蛇 修改成 阿狗,阿猫,阿蛇,并保存,更新到数据库。
客户端2将狗,猫,蛇 修改成 小狗,小猫,小蛇,并保存,
效果图如下:
效果并不好,我们没有给用户做出选择的权利。
演化二:
修改主窗体中保存按钮响应代码:
我们来看看CollisionForm的代码:
你要是注意看就会发现上面显示的,Previous Change的AnimalType为“狗”,而我们希望显示的是“阿狗”。
怎么办呢,我们通过m_errorRow["AnimalType", System.Data.DataRowVersion.Original].ToString();获取得原始只可能是“狗”。这就需要我们在Web服务上动手脚。
演化三:
修改DataService.asmx中的UpdateAnimals代码
上面的代码有这么大魔力?
2、不使用TableAdapter完成一样的效果。
DataService.asmx代码如下:
存储过程:GetAnimals
AND ([AnimalType] = @Original_AnimalType));
存储过程:InsertAnimal
存储过程:DeleteAnimal
存储过程:GetAnimal
其它代码一样。
我们还可以使用IssueVision的并发处理策略,解决的方法很优雅。
我们可以在DataSetAnimals中新建一个表,和Animals表一样,引用相同的表结构,名称为Conficts,当成冲突记录用。
使用RowUpdating,出现错误行就将其添加Conficts中,更新完成后返回。客户端只需取出DataSetAnimals中的Conficts就可以获取冲突信息。
详细可参看IssueVision。
*************************************************************************
作者:a-peng
出处:http://a-peng.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出
原文连接,否则保留追究法律责任的权利。
*************************************************************************