日期:2010-05-15  浏览次数:20419 次

  阅读概要 欢迎参予讨论MARS的使用!通过这里介绍的MARS技术上,你能够在单个连接上执行多重数据库查询。而且依赖于MARS技术的编码更为简单易读,并且使你在开发数据集中的Web应用程序时可以减少内存使用并在一定程序上消除性能瓶颈。难道你不想尝试一下MARS?

  多活动结果集(Multiple Active Result Sets,简称MARS)是ADO.NET 2.0的一个新特征-它允许在单个连接上执行多重的数据库查询或存储过程。这样的结果是,你能够在单个连接上得到和管理多个、仅向前引用的、只读的结果集。在MARS以前,针对每个结果集需要一个独立的连接。当然,你还必须管理这些连接并且要付出相应的内存和潜在的应用程序中的高度拥挤的瓶颈代价-特别是在数据集中的Web应用程序中。

  第一个支持MARS的商业数据库是SQL Server 2005,在本文中你将会详细了解怎样使用这一强有力的然而却是易于添加到ADO.NET开发中去的工具。

  当在以前版本的SQL Server中存取数据结果集时,你需要创建额外的SqlConnection对象以配合使用SqlCommand。你需要追踪你的所有结果集及其导致低效率程序的SqlConnections连接以及"There is already an open DataReader associated with this Connection"错误。现在,使用了MARS技术后,所有这些都成了过去。

  一、 准备工作

  最开始,你需要设置一新的连接字符串以启动多个活动连接。自然地,我们把这个设置命名为"MultipleActiveResultSets",并且如下使用之:

String connectionString = "Data Source=DBSERVER;" +
"Initial Catalog=AdventureWorlds;IntegratedSecurity=SSPI;" +
"MultipleActiveResultSets=True";


  它的默认设定是"False",并且你能明确地禁用它-如果你想传递"False"给这个MultipleActiveResultSets设定的话。

  请遵循下面步骤来建立和启动MARS和ADO.NET 2.0:

  1. 创建一个如上面所示的连接字符串。

  2. 创建一个SqlConnection对象并且用该连接字符串初始化它。

  3. 使用它的Open()方法打开这个SqlConnection对象。

  4. 对于你想要执行的每个查询,创建一个新的SqlCommand对象。把它们与你在上面创建并打开的SqlConnection对象相关联。
 
  5. 使用适当的命令(如,如果你想读该取查询结果的话,可以使用ExecuteReader();或使用ExecuteNonQuery()来进行更新,等等)来执行查询。

  6. 完成后,关闭SqlConnection对象。

  二、实战

  在实际开发中普遍存在的一种典型的从数据库中读写数据的情形是,你可以使用多重连接而现在只用一个连接就足够了。例如,如果你有一些来自于几个表中的数据-它们不能被联结到一个查询中,那么你就会有多重的连接-每个连接都有一个与之相关连的命令用于读取数据。同样,如果你正在向一个表写数据,那么你需要另外一个连接或连接集合-如果有多个表要被更新的话。

  可以考虑这样的情形-你需要读取来自两个查询A和B中的数据-从可能要写向表C的数据获取值,并且对你要写向表D的行为保持一个审计记录。在如此情形中,你的代码可能如下:

  ·为A打开一个连接

  ·执行查询A,并且填充一个数据集

  ·为A关闭一个连接

  ·为B打开一个连接

  ·执行查询B,并且填充一个数据集

  ·为B关闭一个连接

  ·为C打开一个连接

  ·为D打开一个连接

  ·用从A和B中取得的详细数据更新C

  ·用做过的审计标记更新D

  ·关闭D

  ·关闭C

  这是相当复杂的!

  当使用MARS时,你只要完成如下:

  ·用"MultipleActiveResultSets=true"打开连接

  ·执行A并且填充一个数据集

  ·执行B并且填充一个数据集

  ·用从A和B中取得的详细数据更新C

  ·用做过的审计标记更新D

  ·关闭连接

  更简单!

  三、基于MARS和C#的示例分析

  本示例使用了随同SQL Server 2005一起发行的AdventureWorks示例数据库,并且使用了该数据库的开发版。注意,它还要改变该库的一些字段的内容,因此如果你想把这个示例数据库用于别的目的,请注意这一点。

  本示例将展示怎样从数据库中读取一个SalesOrder,然后减少已卖出的项目的库存数额。典型地,这将要求建立到数据库的两个顺序连接-一个用于读取售出的项目数额,另一个用于使用减少的数额来更新库存。

  下面的代码片断显示了怎样在不使用MARS功能的情况下达到这一目的。

ArrayList ids = new ArrayList();
ArrayList qtys = new ArrayList();
string connectionString = "Data Source=MEDIACENTER;" +
 "Initial Catalog=AdventureWorks;Integrated Security=SSPI;" +
 "MultipleActiveResultSets=False";
string strSQLGetOrder = "Select * from Sales.SalesOrderDetail" +
 "WHERE SalesOrderID = 43659";
SqlConnection readConnection = new SqlConnection(connectionString);
readConnection.Open();
SqlCommand readCommand =new SqlCommand(strSQLGetOrder, readConnection);
using (SqlDataReader rdr = readCommand.ExecuteReader()){
 while (rdr.Read()){
  ids.Add(rdr["ProductID"]);
  qtys.Add(rdr["OrderQty"]);
 }
}
readConnection.Close();
string strSQLUpdateInv = "UPDATE Production.ProductInventory " +
 "SET Quantity=Quantity-@amt WHERE (ProductID=@pid)";
SqlConnection writeConnection = new SqlConnection(connectionString);
writeConnection.Open();
SqlCommand writeCommand = new SqlCommand(strSQLUpdateInv,writeConnection);
writeCommand.Parameters.Add("@amt",SqlDbType.Int);
writeCommand.Parameters.Add("@pid",SqlDbType.Int);
for(int lp=0;lp<ids.Count;lp++){
 writeCommand.Parameters["@amt"].Value=qtys[lp];
 writeCommand.Parameters["@pid"].Value=ids[lp];
 writeCommand.ExecuteNonQuery();
}
writeConnection.Close();


  这个示例从数据库中读取单个销售订单(这里,订单号43659被硬编码)-该库中有一项目列表。这些项目应该从库存中扣除,而这是通过第二个连接完成的。然而,为