1、本科毕业设计(论文)外文翻译 毕业设计 (论文 )外文翻译 译文: Visual Studio .NET 如何为并发控制生成 SQL 语句 作者: 史蒂夫斯坦的 Visual Studio 团队 时间: 2002 年 2 月 摘要 :这篇文章研究 Visual Studio .NET 为不同的并发控制 方式所 产生的 SQL 语句, 如何对它们进行修改可以提高执行效率,以及如何生成不带并发控制的 SQL 语句。 引言 任何可能同时被多个用户访问或修改数据的应用程序,都需要进行并发控制。否则 , 一个用户更改记录时可能不经意的覆盖了其他用户 的更改 。 Visual Studio .NET 的设
2、计工具可以生成 “保持所有值 ”方式 的开放式并发 SQL 语句或生成 “最后的更新生效 ”方式的 SQL 语句来更新数据。这篇文章将解释: 不同的 SQL 语句是如何生成的 如何修改自动生成的 SQL 语句可以 提高执行效率 阅读此文章时应具备的一些知识 你需要具备以下知识: 基本的 ADO.NET 概念,包括数据集 (DataSet)以及数据适配器 (DataAdapters)。更多信息请参见 ADO.NET 数据访问介绍 ( Introduction to Data Access with ADO.NET) 。 数据并发机制以及会操作 Visual Studio .NET。更多内容请参见
3、 介绍 ADO.NET 中的数据并发 (Introduction to Data Concurrency in ADO.NET) 。 自动生成的 SQL 语句在哪里 自动生成的 SQL 语句在 command 对象的 CommandText 属性里。在设计阶段配置 DataAdapter 对象时或使用 CommandBuilder 对象时 SQL 命令被自动生成。更多信息,请参见并发与 CommandBuilder 对象( Concurrency and Command Builder Objects) 。 配置 DataAdapter 对象 从工具箱的数据选项卡中拖一个 DataAdapte
4、r 对象 从服务器资源管理器拖一个数据表 选中已有的 DataAdapter 对象,然后单击在属性窗口底部的 “ 配置数据适配器 ” 链接 CommandBuilder 对象 CommandBuilder 对象在运行时刻被创建,更多信息请参阅 SqlCommandBuilder 或OleDbCommandBuilder。 并发控制与数据适配器 (DataAdapter) 使用 “ 数据适配器 配置 向导 ” 配置数据适配器时,你可以选择是否使用开放式并发来生 成 Update 和 Delete 语句。 本科毕业设计(论文)外文翻译 一些思考和注意事项 你的数据源必须有一个主键才能以开放式并发方
5、式生成 SQL 语句 当使用从 “ 服务器资源管理器 ” 拖放一个数据表的方式来创建 DataAdapter 对象时,DataAdapter 对象自动生成基于开放式并发的 Update 和 Delete 语句。如果你不想使用开放式并发, 右击 DataAdapter 对象, 从快捷菜单中选择 “配置数据适配器 ”,然后 在“ 高级 SQL 生成选项 ” 对话框中清除 “ 使用开放式并发 ” 选项 的选定 。向导则会重新创建不带并发检测的 SQL 语句。 当重新配置现有的 DataAdapter 时,应注意 “ 高级 SQL 生成选项” 对话框里的选项已经全部恢复默认。例如最初配置 DataAd
6、apter 时没有 选定“ 使用开放式并发 ”选项 ,但是当 重新配置 DataAdapter 时, “使用 开放式并发 ” 选项却会被选定,即便你根本没有打开过 “ 高级 SQL 生成选项 ” 对话框。 如果你在 “数据适配器配置 向导 ” 的“选择查询类型”页面 选择 “ 使用 现 有的存储过程 ” ,则 “使用开放式并发 ”选项将不可用。存储过程仍按其原来的方式执行。如果想使用并发检测的话,必须将其包括到存储过程中、或在你的应用程序中编写 相应的代码 。 当使用开放式并发来创建 SQL 命令时,不 会 对二进制 数据 列验证 进行 并发 处理 。 这将导致 用这种方法对大 的 二进制记录
7、集执行按位比较算法时 的 效率低 下 。 用向导生成 SQL 语句 为了理解 Visual Studio .NET 如何使用开放式并发来生成 SQL 语句,让我们来看看用 “ 数 据适配器 配置 向导 ” 生成的 Update 语句。我们将查看同一条语句在选择 “使用 开放式并发 ” 选项和不选择 “使用 开放式并发 ” 选项 时的 不同状态。 你会注意到,选择开放式并发与不选择开放式并发所生成 SQL 语句的区别只 存 在于 Where子句上。 注: 以下的例子使用 用“ 数据适配器 配置 向导 ” 生成的 Update 语句,并 从 NorthWind示例数据库的 Customers 表中
8、选择了若干列。 使用开放式并发的 Update 语句 这个例子使用了 “ 数据适配器 配置 向导 ” 的默认 配置 ,即 选中了“ 使用开放式并发 ”选项 。 注 : 当使用开放式并发时,生成的 command 的参数集里还 存在 一个参 数副本。第二个参数集(带 Original_前缀的那个)保存了最初从数据源里读取的值。 检查 Where 子句发现,每一个生成的语句都要检测数据库当前的值是否等于最初读取的值(例, WHERE City = Original_City)。通过数据库中的每个字段与最初读取的值相比较,我们很容易确定是否同时有其他用户修改了某个字段。如果 Where 子句不 成立
9、 ,就没有记录会被修改, 与此 同时还引发了一个 “ 数据库并发 ” 异常。如果数据源的某个字段 为 空值( NULL),生成的 SQL 语句同样验证最初读取的记录是否 也为 空值。 UPDATE Customers SETCustomerID = CustomerID, CompanyName = CompanyName, ContactName = ContactName, ContactTitle = ContactTitle, City = City WHERE (CustomerID = Original_CustomerID) AND (City = Original_City 本
10、科毕业设计(论文)外文翻译 OR Original_City IS NULL AND City IS NULL) AND (CompanyName = Original_CompanyName) AND (ContactName = Original_ContactName OR Original_ContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = Original_ContactTitle OR Original_ContactTitle IS NULL AND ContactTitle IS NULL); SEL
11、ECTCustomerID, CompanyName, ContactName, ContactTitle, City FROM Customers WHERE (CustomerID = CustomerID) 不使用开放式并发的 Update 语句 这个例子更改了“数据适配器配置向导”的高级选项,没有选中“使用开放式并发”选项。 以下的语句表明:只要数据库中一条记录满足 CustomerID = Original_CustomerID,则所有的字段都会被更新。不管这条记录现在是什么样的值,它都将被 设置为通过 SQL 语句传递到数据源的值。在这里没有任何关于并发的检测,也无法得知是否同时有
12、其它用户在更改这条记录。这种方式称为 “ 最后的更新生效 ” 方式。无论以前对这条记录进行过什么样的修改,更新操作都会执行。 UPDATE Customers SETCustomerID = CustomerID, CompanyName = CompanyName, ContactName = ContactName, ContactTitle = ContactTitle, City = City WHERE (CustomerID = Original_CustomerID); SELECT CustomerID, CompanyName, ContactName, ContactTit
13、le, City FROM Customers WHERE (CustomerID = CustomerID) 优化生成的 SQL 语句 Visual Studio .NET 生成 “保持所有值 ”方式 的 SQL 语句来 实现 开放式并发。虽然 这 可能 没 有生成 最 高 效的 SQL 语句,但是它 的却 生成 了 可以对数据源所有列(包括主键)进行并发检测的 SQL 语句。 使用 “保持所有值 ”方式实现开放式并发,当执行效率非常低下时,你可以手工修改生成的 SQL 语句以使它们不检查数据源的所有列。最常见的方式是使用时间戳或版本号字段。如果你的数据源包含一个每次修改记录时都会更新的时间
14、戳字段,你只需要验证数据源中的时间戳和你程序中的时间戳二者是否匹配,就可以知道是否同时有其他用户修改了记录。 下面这条 SQL 语句使用检查时间戳模式。 注: 这个例子假设数据库已经设置了时间戳 字段 UPDATE Customers SET CustomerID = CustomerID, CompanyName = CompanyName, ContactName = ContactName, ContactTitle = ContactTitle, City = City WHERE (CustomerID = Original_CustomerID) AND (TimeStamp = Original_TimeStamp); SELECT CustomerID, CompanyName, ContactName, ContactTitle, City, TimeStamp FROM Customers WHERE (CustomerID = CustomerID) 并发与 CommandBuilder 对象