| >
ADO.NET 的事务模型已经更改。在 ADO 中,当调用 StartTransaction 时,调用之后的任何更新操作都被视为是事务的一部分。但是,在 ADO.NET 中,当调用 Connection.BeginTransaction 时,会返回一个 Transaction 对象,需要把它与 Command 的 Transaction 属性联系起来。这种设计可以在一个单一连接上执行多个根事务。如果未将 Command.Transaction 属性设置为一个针对相关的 Connection 而启动的 Transaction,那么 Command 就会失败并引发异常。
即将发布的 .NET 框架将使您可以在现有的分布式事务中手动登记。这对于对象池方案来说很理想;在该方案中,一个池对象打开一次连接,但是在多个独立的事务中都涉及到该对象。.NET 框架 1.0 发行版中这一功能并不可用。
有关事务的更多信息,请参阅 Performing Transactions 以及 .NET Data Access Architecture Guide。
返回页首
使用连接
高性能应用程序与使用中的数据源保持最短时间的连接,并且利用性能增强技术,例如连接池。下面的主题提供一些技巧,有助于在使用 ADO.NET 连接到数据源时获得更好的性能。
连接池
用于 ODBC 的 SQL Server、OLE DB 和 .NET 框架数据提供程序隐式缓冲连接。通过在连接字符串中指定不同的属性值,可以控制连接池的行为。有关如何控制连接池的行为的详细信息,请参阅 Connection Pooling for the SQL Server .NET Data Provider 和 Connection Pooling for the OLE DB .NET Data Provider。
用 DataAdapter 优化连接
DataAdapter 的 Fill 和 Update 方法在连接关闭的情况下自动打开为相关命令属性指定的连接。如果 Fill 或 Update 方法打开了连接,Fill 或 Update 将在操作完成的时候关闭它。为了获得最佳性能,仅在需要时将与数据库的连接保持为打开。同时,减少打开和关闭多操作连接的次数。
如果只执行单个的 Fill 或 Update 方法调用,建议允许 Fill 或 Update 方法隐式打开和关闭连接。如果对 Fill 和/或 Update 调用有很多,建议显式打开连接,调用 Fill 和/或 Update,然后显式关闭连接。
另外,当执行事务时,显式地在开始事务之前打开连接,并在提交之后关闭连接。例如:
''''Visual Basic
Public Sub RunSqlTransaction(da As SqlDataAdapter, myConnection As SqlConnection, ds As DataSet)
myConnection.Open()
Dim myTrans As SqlTransaction = myConnection.BeginTransaction()
myCommand.Transaction = myTrans
Try
da.Update(ds)
myTrans.Commit()
Console.WriteLine("Update successful.")
Catch e As Exception
Try
myTrans.Rollback()
Catch ex As SqlException
If Not myTrans.Connection Is Nothing Then
Console.WriteLine("An exception of type " & ex.GetType().ToString() & _
" was encountered while attempting to roll back the transaction.")
End If
End Try
Console.WriteLine("An exception of type " & e.GetType().ToString() & " was encountered.")
Console.WriteLine("Update failed.")
End Try
myConnection.Close()
End Sub
//C#
public void RunSqlTransaction(SqlDataAdapter da, SqlConnection myConnection, DataSet ds)
{
myConnection.Open();
SqlTransaction myTrans = myConnection.BeginTransaction();
myCommand.Transaction = myTrans;
try
{
da.Update(ds);
myCommand.Transaction.Commit();
Console.WriteLine("Update successful.");
}
catch(Exception e)
{
try
{
myTrans.Rollback();
}
catch (SqlException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine("An exception of type " + ex.GetType() +
" was encountered while attempting to roll back the transaction.");
}
}
Console.WriteLine(e.ToString());
Console.WriteLine("Update failed.");
}
myConnection.Close();
}
始终关闭 Connection 和 DataReader
完成对 Connection 或 DataReader 对象的使用后,总是显式地关闭它们。尽管垃圾回收最终会清除对象并因此释放连接和其他托管资源,但垃圾回收仅在需要时执行。因此,确保任何宝贵的资源被显式释放仍然是您的责任。并且,没有显式关闭的 Connections 可能不会返回到池中。例如,一个超出作用范围却没有显式关闭的连接,只有当池大小达到最大并且连接仍然有效时,才会被返回到连接池中。
注 不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 或 Dispose。最后完成的时候,仅释放类自己直接拥有的非托管资源。如果类没有任何非托管资源,就不要在类定义中包含 Finalize 方法。
在 C# 中使用 "Using" 语句
对于 C# 程序员来说,确保始终关闭 Connection 和 DataReader 对象的一个方便的方法就是使用 using 语句。using 语句在离开自己的作用范围时,会自动调用被“使用”的对象的 Dispose。例如:
//C#
string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
}
}
Using 语句不能用于 Microsoft庐 Visual Basic庐 .NET。
避免访问 OleDbConnection.State 属性
如果连接已经打开,OleDbConnection.State 属性会对 DBPROP_CONNECTIONSTATUS 属性的 DATASOURCEINFO 属性集执行本地 OLE DB 调用 IDBProperties.GetProperties,这可能会导致对数据源的往返行程。也就是说,检查 State 属性的代价可能很高。所以仅在需要时检查 State 属性。如果需要经常检查该属性,监听 OleDbConnection 的 StateChange 事件可能会使应用程序的性能好一些。有关 StateChange 事件的详细信息,请参阅 Working with Connection Events。
返回页首
与 XML 集成
ADO.NET 在 DataSet 中提供了广泛的 XML 集成,并公开了 SQL Server 2000 及其更高版本提供的部分 XML 功能。还可以使用 SQLXML 3.0 广泛地访问 SQL Server 2000 及其更高版本中的 XML 功能。下面是使用 XML 和 ADO.NET 的技巧和信息。
DataSet 和 XML
DataSet 与 XML 紧密集成,并提供如下功能:
•
从 XSD 架构中加载 DataSet 的架构或关系型结构。
•
从 XML 加载 DataSet 的内容。
•
如果没有提供架构,可以从 XML 文档的内容推断出 DataSet 的架构。
•
把 DataSet 的架构写成 XSD 架构。
•
把 DataSet 的内容写成 XML。
•
同步访问使用 DataSet 的数据的关系表示,以及使用 XmlDataDocument 的数据的层次表示。
注 可以使用这种同步把 XML 功能(例如,XPath 查询和 XSLT 转换)应用到 DataSet 中的数据,或者在保留原始 XML 保真度的前提下为 XML 文档中数据的全部或其中一个子集提供关系视图。
关于 DataSet 提供的 XML 功能的详细信息,请参阅 XML and the DataSet。
架构推断
从 XML 文件加载 DataSet 时,可以从 XSD 架构加载 DataSet 架构,或者在加载数据前预定义表和列。如果没有可用的 XSD 架构,而且不知道为 XML 文件的内容定义哪些表和列,就可以在 XML 文档结构的基础上对架构进行推断。
架构推断作为迁移工具很有用,但应只限于设计阶段应用程序,这是由于推断处理有如下限制。
•
对架构的推断会引入影响应用程序性能的附加处理。
•
所有推断列的类型都是字符串。
•
推断处理不具有确定性。也就是说,它是基于 XML 文件内容的,而不是预定的架构。因此,对于两个预定架构相同的 XML 文件,由于它们的内容不同,结果得到两个完全不同的推断架构。
有关更多信息,请参阅 Inferring DataSet Relational Structure from XML。
用于 XML 查询的 SQL Server
如果正从 SQL Server 2000 FOR XML 返回查询结果,可以让用于 SQL Server 的 .NET 框架数据提供程序使用 SqlCommand.ExecuteXmlReader 方法直接创建一个 XmlReader。
SQLXML 托管类
.NET 框架中有一些类,公开用于 SQL Server 2000 的 XML 的功能。这些类可在 Microsoft.Data.SqlXml 命名空间中找到,它们添加了执行 XPath 查询和 XML 模板文件以及把 XSLT 转换应用到数据的能力。
SQLXML 托管类包含在用于 Microsoft SQL Server 2000 的 XML (SQLXML 2.0) 发行版中,可从 XML for Microsoft SQL Server 2000 Web Release 2 (SQLXML 2.0) ??μ?。
返回页首
更多有用的技巧
下面是一些编写 ADO.NET 代码时的通用技巧。
避免自动增量值冲突
就像大多数数据源一样,DataSet 使您可标识那些添加新行时自动对其值进行递增的列。在 DataSet 中使用自动增量的列时,如果自动增量的列来自数据源,可避免添加到 DataSet 的行和添加到数据源的行之间本地编号冲突。
例如,考虑一个表,它的主键列 CustomerID 是自动增量的。两个新的客户信息行添加到表中,并接收到自动增量的 CustomerID 值 1 和 2。然后,只有第二个客户行被传递给 DataAdapter 的方法 Update,新添加的行在数据源接收到一个自动增量的 CustomerID 值 1,与 DataSet 中的值 2 不匹配。当 DataAdapter 用返回值填充表中第二行时,就会出现约束冲突,因为第一个客户行已经使用了 CustomerID 值 1。
要避免这种情况,建议在使用数据源上自动增量的列以及 DataSet 上自动增量的列时,把 DataSet 中的列创建为 AutoIncrementStep 值等于 -1 并且 AutoIncrementSeed 值等于 0,另外,还要确保数据源生成的自动增量标识值从 1 开始,并且以正阶值递增。因此,DataSet 为自动增量值生成负数,与数据源生成的正自动增量值不冲突。另外一个选择是使用 Guid 类型的列,而不是自动增量的列。生成 Guid 值的算法应该永远不会使数据源中生成的 Guid 值与 DataSet 中生成的 Guid 值一样。
如果自动增量的列只是用作唯一值,而且没有任何意义,就考虑使用 Guid 代替自动增量的列。它们是唯一的,并且避免了使用自动增量的列所必需的额外工作。
有关从数据源检索自动增量的列值的示例,请参阅 Retrieving Identity or AutoNumber Values。
检查开放式并发冲突
按照设计,由于 DataSet 是与数据源断开的,所以,当多个客户端在数据源上按照开放式并发模型更新数据时,需要确保应用程序避免冲突。
在测试开放式并发冲突时有几项技术。一项技术涉及在表中包含时间戳列。另外一项技术是,验证一行中所有列的原始值是否仍然与通过在 SQL 语句中使用 WHERE 子句进行测试时在数据库中找到的值相匹配。
有关包含代码示例的该主题的详细讨论,请参阅 Optimistic Concurrency。
多线程编程
ADO.NET 对性能、吞吐量和可伸缩性进行优化。因此,ADO.NET 对象不锁定资源,并且必须只用于单线程。一个例外是 DataSet,它对多个阅读器是线程安全的。但 上一页 [1] [2] [3] [4] 下一页 |