ADO.NET 中的数据并发
当多个用户试图同时修改数据时,需要建立控制机制来防止一个用户的修改对同时操作的其他用户所作的修改产生不利的影响。处理这种情况的系统叫做“并发控制”。
并发控制的类型
通常,管理数据库中的并发有三种常见的方法:
?保守式并发控制 - 在从获取记录直到记录在数据库中更新的这段时间内,该行对用户不可用。
?开放式并发控制 - 只有当实际更新数据时,该行才对其他用户不可用。更新将在数据库中检查该行并确定是否进行了任何更改。如果试图更新已更改的记录,则将导致并发冲突。
?最后的更新生效 - 只有当实际更新数据时,该行才对其他用户不可用。但是,不会将更新与初始记录进行比较;而只是写出记录,这可能就改写了自上次刷新记录后其他用户所进行的更改。
保守式并发
保守式并发通常用于两个目的。第一,在某些情况下,存在对相同记录的大量争用。在数据上放置锁所费的成本小于发生并发冲突时回滚更改所费的成本。
在事务过程中不宜更改记录的情况下,保守式并发也非常有用。库存应用程序便是一个很好的示例。假定有一个公司代表正在为一名潜在的客户检查库存。您通常要锁定记录,直到生成订单为止,这通常会将该项标记为“已订购”状态并将其从可用库存中移除。如果未生成订单,则将释放该锁,以便其他检查库存的用户得到准确的可用库存计数。
但是,在断开的结构中无法进行保守式并发控制。连接打开的时间只够读取数据或更新数据,因此不能长时间地保持锁。此外,长时间保留锁的应用程序将无法进行伸缩。
注意 如果基础数据源支持事务,则可以通过在事务中更新数据来模拟保守式并发。有关更多信息,请参见 ADO.NET 中的事务。
开放式并发
在开放式并发中,只有在访问数据库时才设置并保持锁。这些锁将防止其他用户在同一时间更新记录。除了进行更新这一确切的时刻之外,数据始终可用。有关更多信息,请参见开放式并发。
当试图更新时,已更改行的初始版本将与数据库中的现有行进行比较。如果两者不同,更新将失败,并引发并发错误。这时,将由您使用所创建的业务逻辑来协调这两行。
最后的更新生效
当使用“最后的更新生效”时,不会对初始数据进行检查,而只是将更新写入数据库。很明显,可能会发生以下情况:
?用户 A 从数据库获取一项记录。
?用户 B 从数据库获取相同的记录,对其进行修改,然后将更新后的记录写回数据库。
?用户 A 修改“旧”记录并将其写回数据库。
在上述情况中,用户 A 永远也不会看到用户 B 作出的更改。如果您计划使用并发控制的“最后的更新生效”方法,则要确保这种情况是可以接受的。
ADO.NET 和 Visual Studio .NET 中的并发控制
因为数据结构基于断开的数据,所以 ADO.NET 和 Visual Studio .NET 使用开放式并发。因此,您需要添加业务逻辑,以利用开放式并发解决问题。
如果您选择使用开放式并发,则可以通过两种常规的方法来确定是否已发生更改:版本方法(实际版本号或日期时间戳)和保存所有值方法。
版本号方法
在版本号方法中,要更新的记录必须具有一个包含日期时间戳或版本号的列。当读取该记录时,日期时间戳或版本号将保存在客户端。然后,将对该值进行部分更新。
处理并发的一种方法是仅当 WHERE 子句中的值与记录上的值匹配时才进行更新。该方法的 SQL 表示形式为:
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE DateTimeStamp = @origDateTimeStamp或者,可以使用版本号进行比较:
UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE RowVersion = @origRowVersionValue如果日期时间戳或版本号匹配,则表明数据存储区中的记录未被更改,并且可以安全地使用数据集中的新值对该记录进行更新。如果不匹配,则将返回错误。您可以编写代码,在 Visual Studio .NET 中实现这种形式的并发检查。您还必须编写代码来响应任何更新冲突。为了确保日期时间戳或版本号的准确性,您需要在表上设置触发器,以便在发生对行的更改时,对日期时间戳或版本号进行更新。
保存所有值方法
使用日期时间戳或版本号的替代方法是在读取记录时获取所有字段的副本。ADO.NET 中的 DataSet 对象维护每个修改记录的两个版本:初始版本(最初从数据源中读取的版本)和修改版本(表示用户更新)。当试图将记录写回数据源时,数据行中的初始值将与数据源中的记录进行比较。如果它们匹配,则表明数据库记录在被读取后尚未经过更改。在这种情况下,数据集中已更改的值将成功地写入数据库。
对于数据适配器的四个命令(DELETE、INSERT、SELECT 和 UPDATE)来说,每个命令都有一个参数集合。每个命令都有用于初始值和当前值(或修改值)的参数。
注意 由于不存在初始记录,添加新记录(INSERT 命令)只需要当前值;移除记录(DELETE 命令)只需要使用初始值来定位要删除的记录。
以下示例显示一个数据集命令的命令文本,该命令更新一个典型的客户表。该命令是为动态 SQL 和开放式并发而指定的。UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,
PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)
AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)
复制代码请注意,九个 SET 语句参数表示将写入数据库的当前值,而九个 WHERE 语句参数则表示用于定位初始记录的初始值。
前九个 SET 语句参数对应于参数集合中的前九个参数。这些参数会将其 SourceVersion 属性设置为 Current。
接着的九个 WHERE 语句参数用于开放式并发。这些占位符对应于参数集合中接着的九个参数,这些参数的每一个都将其 SourceVersion 属性设置为 Original。
SELECT 语句用于在发生更新后刷新数据集。它是您在“高级 SQL 生成选项”对话框中设置“刷新数据集”选项时生成的。
注意 上面的 SQL 使用命名参数,而 OleDbDataAdapter 命令则使用问号 (?) 作为参数占位符。
默认情况下,如果您在“数据适配器配置向导”中选择“开放式并发”选项,Visual Studio 将为您创建这些参数。此时将由您根据自己的业务要求来添加错误处理代码。ADO.NET 提供了一个 DBConcurrencyException 对象,它返回违反并发规则的行。有关更多信息,请参见处理并发错误。
摘自:http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vbcon/html/vbtskPerformingOptimisticConcurrencyChecking.asp
ADO.NET 中的数据并发的更多相关文章
- ado.net中,数据的批量处理
//btBigImport按钮点击事件 private void btBigImport_Click(object sender, RoutedEventArgs e) { //连接字符 ...
- ADO.NET 中的新增功能
ADO.NET 中的新增功能: .NET Framework (current version) 以下是 .NET Framework 4.5 中 ADO.NET 的新增功能. SqlClient D ...
- Oracle的数据并发与一致性详解(下)
上篇介绍了数据并发与一致性的相关概念.以及oracle的事务隔离级别等内容,本篇继续介绍锁机制.自动锁.手动锁.用户自定义锁的相关内容. 请尊重作者劳动成果,转载请标明原文链接: https://ww ...
- [翻译]比较ADO.NET中的不同数据访问技术(Performance Comparison:Data Access Techniques)
Performance Comparison: Data Access Techniques Priya DhawanMicrosoft Developer Network January 2002 ...
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
- 第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据
第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据 ADO.NET 为什么要学习? 我们要搭建一个平台(Web/Winform ...
- ADO.NET中DataSet、DataTable、DataRow的数据复制方法
DataSet 对象是支持 ADO.NET的断开式.分布式数据方案的核心对象 ,用途非常广泛.我们很多时候需要使用其中的数据,比如取得一个DataTable的数据或者复制另一个DataTabe中的数据 ...
- 【ADO.NET】3、从TXT中导入数据到数据库
数据库字段与类型id int,Name nvarchar(20),Age int TXT文本内容为 小高-20张三-18李四-19 private void btnInput_Click(object ...
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...
随机推荐
- lintcode:Search Insert Position 搜索插入位置
题目: 搜索插入位置 给定一个排序数组和一个目标值,如果在数组中找到目标值则返回索引.如果没有,返回到它将会被按顺序插入的位置. 你可以假设在数组中无重复元素. 样例 [1,3,5,6],5 → 2 ...
- lintcode:搜索二维矩阵II
题目 搜索二维矩阵 II 写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数. 这个矩阵具有以下特性: 每行中的整数从左到右是排序的. 每一列的整数从上到下是排序的. 在每一行或每一列中没 ...
- Python Snippet
python按行读取文件,如何去掉换行符"\n" for line in file.readlines(): line=line.strip('\n') python没有subst ...
- Orcle数据库查询练习复习:一
一.创建数据库和表 drop table student; create table student ( sid int, sname ), sage int, ssex ), snativeplac ...
- [翻译] - <Entity Framework> - 直接执行数据库命令
原文:[翻译] - <Entity Framework> - 直接执行数据库命令 纯属学习上的记录, 非专业翻译, 如有错误欢迎指正! 原文地址: http://msdn.microsof ...
- Objective-C命名编写规范
There are only two hard things in Computer Science: cache invalidation and naming things. 在计算机科学中只有两 ...
- Redis cluster学习 & Redis常识 & sort操作
Redis中的5种数据类型String.Hash.List.Set.Sorted Set. Redis源码总代码一万多行. 这篇文章有一些Redis "常识" http://www ...
- javascript插件编写小结
写JS插件,最好是先通过HTML方式将展示结果显示出来,然后再封装成JS插件,将其画出来.JS模板如下: (function($){ $.fn.fnName = function(options){ ...
- [Sciter系列] MFC下的Sciter–5.Sciter中GUI线程研究
[Sciter系列] MFC下的Sciter–5.Sciter中GUI线程研究,目前MFC存在问题,win32没问题. 本系列文章的目的就是一步步构建出一个功能可用,接口基本完善的基于MFC框架的Sc ...
- UVA 821 Page Hopping 网页跳跃(BFS,简单)
题意: 给一个无权有向图,可认为边的长度为1,求两点间的平均长度(即所有点对的长度取平均),保留3位小数.保证任意点对都可达. 思路: 简单题.直接穷举每个点,进行BFS求该点到其他点的距离.累加后除 ...