博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

DataSet 和 DataReader(转贴)

Posted on 2006-02-13 17:03  程序生活  阅读(645)  评论(0编辑  收藏  举报

运用DataReader类
下面就是运用DataReader类的理想条件:

  • 你读取的数据必须是新的,所以在每次需要数据的时候,你都必须从数据库读取。创建一个DataReader类不会消耗很多内存,不过随着负荷的增加,DataSet上的性能也会很快地提高(参考资源中Visual Studio Magazine中的文章)。
  • 你对每行数据的需求很简单。该情况的最好的例子就是简单地将DataReader绑定到一个Web控件,如DataGrid或DropDownList。
  • 你只需要从数据库中以只向前的(forward-only) 、只读的形式来存取XML数据。在这种情况下,你可以用SQLCommand对象的ExcecuteXmlReader()方法来得到一个XmlReader类(相当于XML版的DataReader)。这就需要一个运用FOR XML子句的SQL Server查询,或者一个包含有效XML的ntext字段。
  • 你计划对数据库进行几个重复的调用,来读取一小块信息。在这种情况下,我们前面提到过的性能数据会有更大的提高。
  • 的确,使DataSet类更强大的许多功能只适用于基于客户端的Windows Form应用程序,比如在多个表之间建立关系的功能。在很多情况下,DataSet类都比DataReader类更有优势,而且在有些情况下,你根本就不能用DataReader类。
  • 运用DataSet类
    在下面的情况,你应该考虑运用DataSet类:

  • 你构建了一个Web service,它运用的数据是你作为返回值读取的数据。因为DataReader类必须保持到数据库的连接,所以它们不能被序列化到XML中,也不能被发送给一个Web service的调用者。
  • 你需要排序或筛选数据。在运用一个DataView对象(呈现为DataTable类的DefaultView属性,它包含一个DataSet类)来排序或筛选数据前,我们先试着用SQL查询(如WHERE和ORDER BY语句)来实现这些功能,并运用更轻量级、更快的DataReader类。然而,有时侯用这种方法是不行的,或者当你需要多次地对数据进行排序或筛选时就不能用DataReader。
  • 针对同一请求,你需要多次遍历数据。你只能在DataReader中循环一次。如果你想将多个ServerControl类绑定到同一个数据集,那么选择DataSet就更好。DataReader类不能被绑定到多个ServerControl类,因为它是只向前读取的。在这种情况下,如果要使用DataReader,必须从数据库读取两次数据。
  • 你需要存储数据,而后续的页面请求可能会用到的这些数据。如果数据只被请求它的专门的人使用,你可以将DataSet类保存在一个Session变量中。如果数据可以被任何人访问,那么你可以将它保存在一个Application变量中,或保存在Cache中(我建议使用后一种方法,因为它支持时间期限和回调(callback))。因为DataReader类必须一直打开对数据库的连接,而且它一次只能保存一行数据,所以它们不能在跨页面请求中被保存。
  • 你需要对一个结果集的每个元素实现特殊的、耗时的功能。例如,如果你从一个数据库读取一列邮政编码,并想通过调用一个Web service来得到每个地区的详细的天气状况信息,那么选择DataSet就会更好。这是因为,当你在用DataReader类时,在关闭DataReader类前,与数据库的连接不会被释放回连接池。在数千页面请求之间潜在的一个很小的延时都会造成Web应用程序的很高的访问量,从而就会消耗完可用的连接。相反,DataSet可以在前端读取所有的数据,并可以马上关闭与数据库的连接,将它返回到连接池,因此其它的页面请求就可以用这个连接了。
  • 你需要在一个两维范例中加载并处理XML数据。DataSet类对于XML很有用,因为你可以将DataView用于XML,对根本的数据进行排序和筛选,就同处理一个数据库结果集一样。然而,需要注意的是在System.Xml名字空间中有很多类,你可以将它们用于更复杂的XML操作。
  • 你的数据源不是一个数据库。虽然OleDbDataReader可以用于任何OLEDB数据提供者(可能指向一个数据库,也可能不指向一个数据库),但DataSet对象可以从一个XML文件直接加载数据,并动态地解释它的schema。DataSet类也可以将XML数据写回一个数据流或一个文件。
  • 从上面的讲述我们就可以看到,DataSet类比DataReader类有更多的功能,这就可以让你在更多的情况下运用它们。但这并不意味着你总是在用DataSet类。你需要在ASP.NET中完成的相当大一部分的任务都属于DataReader的范畴。

    尽管如此,毫无疑问,从重要程度或复杂程度的角度来说,DataSet类在很多ASP.NET Web应用程序中都起着很重要的作用。你可以通过明智的缓存来最小化数据库往返,从而降低DataSet类的“性能损害”。DataReader和DataSet都是一个成功的ASP.NET Web应用程序的重要的部件。重要的是,我们需要了解何时、在哪里可以最好的使用它们。




    使用DataSet是为了实现应用程序的下述功能:

      l 操作结果中的多个分离的表。

      l 操作来自多个源(例如来自多个数据库、XML文件和电子表格的混合数据)的数据。

      l 在层之间交换数据或使用XML Web服务。与DataReader 不同,DataSet能被传递到远程客户端。

      l 通过缓冲重复使用相同的行集合以提高性能(例如排序、搜索或过滤数据)。

      l 每行执行大量的处理。在使用DataReader返回的行上进行扩展处理将使连接存在的时间比必要的更长,从而降低效率。

      l 使用XML操作(例如XSLT转换和Xpath查询)维护数据。

      在应用程序需要以下功能时使用DataReader:

      l 不需要缓冲数据。

      l 正在处理的结果集太大而不能全部放入内存中。

      l 需要迅速一次性访问数据,采用只向前的只读的方式。

      注意:当填充DataSet的时候,DataAdapter使用DataReader。因此使用DataAdapter代替DataSet获得的性能是节约了DataSet消耗的内存和组装DataSet所需要的周期。这种性能的提高大部分是有名无实的,因此你应该根据需要的功能为基础来做设计决定。

      使用强类型DataSet的好处

      使用DataSet的另一个好处是它能被继承用于建立强类型的DataSet。强类型DataSet的好处包括设计时的检查和强类型DataSet 的Visual Studio .NET语句填充。当你为DataSet固定了大纲或关系结构时,就能建立强类型DataSet,把行和列作为对象的属性而不是项的集合。例如,作为暴露顾客表的某一行的列名的代替,你可以暴露Customer对象的 Name属性。强类型的DataSet衍生自DataSet类,因此不会牺牲DataSet的任何功能,也就是说,强类型的DataSet也可以是远程的,并作为数据绑定控件(例如DataGrid)的数据源提供。如果不知道大纲,也能通过使用通常的DataSet获得好处,但是丧失了强类型DataSet的附加特性。

      在强类型DataSet中处理空值

      使用强类型DataSet时,你能给DataSet 的XML大纲定义语言(XSD)作注解以确保强类型DataSet正确的处理空(Null)的引用。空值(nullValue)注释使你能用String.Empty这个特定值代替DBNull、保持了空引用、或者产生一个异常。选择其中的哪个依赖于应用程序的内容,默认情况下遇到空引用将产生一个异常。

      刷新DataSet中的数据

      如果你希望使用更新后的值从服务器刷新数据集中的值,使用DataAdapter.Fill。如果主键定义在数据表上,DataAdapter.Fill基于主键匹配新行,并把服务器的数据改成已存在的行。被刷新行的RowState设置为Unchanged,即使在刷新前它被修改过。注意如果给数据表定义了主键,DataAdapter.Fill添加新行可能重复主键值。

      如果希望用服务器的当前值刷新一个表,并且保持表中行的改变,你必须首选使用DataAdapter.Fill组合它,填充一个新的数据表,接着将该数据表合并(Merge)进一个数据集,并把preserveChanges值设为true。

      在DataSet中搜索数据

      在一个数据集中查询符合特定条件的行时,使用基于索引(index-based)的查看表将提高性能。给数据表指定主键(PrimaryKey)值时,就建立了一个索引。当为数据表建立数据视图(DataView)时也建立了索引。下面是一些使用基于索引查看的技巧:

      如果查询是在数据表的主键列上进行的,使用DataTable.Rows.Find代替DataTable.Select。

      查询非主键列,可以使用数据视图来提高多个数据查询的速度。当给数据视图添加排序时,将建立搜索时使用的索引。数据视图暴露了查询下层数据表的Find和FindRows方法。

      如果你不是查询表的排序视图,也可以通过为数据表建立数据视图获得基于索引的查看表的好处。注意如果你执行数据上的多个查询这是唯一的好处。如果你只执行单个查询,需要建立索引的过程将因为使用索引而降低了性能。

      数据视图(DataView)结构

      当数据视图建立后,并且当Sort、RowFilter或RowStateFilter或者属性被修改时,数据视图为下层数据表中的数据建立索引。当建立数据视图对象时,使用把Sort、RowFilter和RowStateFilter值作为参数的数据视图构造函数。结果是建立了一次索引。建立"空"数据视图,然后设置Sort、RowFilter和RowStateFilter属性将导致至少两次建立索引。




    When I talk with working developers, the question I hear most often is: Which is the right approach? The answer depends on your problem domain. The DataReader is a forward-only fire hose for data. It is often the perfect solution for reporting on data in the database. But forcing a design to use it may involve writing your own DataSet-like container for data if you need to use the data after you read a single row.

    The DataSet, on the other hand, is a great way to hold data from the database, but filling it comes with a performance penalty. If you need to manipulate your data and save it back to the database, the DataSet is really the only game in town. Using the DataSet to simply report on data (like on a Web page, for instance) usually is the wrong approach. I say "usually" because there are always exceptions to this rule.

    Let's look at a specific domain problem: an e-commerce site. Assuming we have a large number of salable items, I would use DataReaders to show the user the products they are looking for and a DataSet for the shopping basket. When you list products by caching all the items in your catalog, you usually lose efficiency when the cache is too large. I usually like to let the database handle the caching of recently used items. It does a better job in most cases. But a smaller DataSet to contain the user's information and shopping basket could be cached in the Web session so that we can limit the number of database reads and writes. If the visitor never ends up buying anything, their shopping basket could simply disappear (and never get persisted) when his or her session dies.

    Just remember this caveat: If you need it cached, use a DataSet; if you need it once, use a DataReader.


    在如下场合下考虑使用DataReader:

    • 当应用程序要求优化只读以及前向数据访问(如绑定DataGrid控件)时,DataReader是一个更好的选项。当数据从DataReader“卸下”来时,就关闭连接,这对提供程序的性能有帮助。
    • 当你打算重复性的检索少量数据或者你检索的数据在每次使用数据时它们都需要尽可能的更新时,最好使用DataReader。


    在如下场合下考虑使用DataSet:

    • 如果应用程序不是立即“卸载”查询结果时,或者有大量的处理(如两次数据访问之间的事务逻辑处理)时,最好使用DataSet 。DataSet检索数据后,将检索结果存放到内存中去,并同时把连接返回到数据库连接池中,这样DataReader可以在处理完成之前保持连接锁定在开启的状态。这个特性会非常容易的导致高流量的应用程序耗尽所有可用的数据库连接。
    • 当你需要多次操作数据时,最好使用DataSet。例如,当多个控件需要获取同样的数据时,使用DataSet就比DataReader更加合适。这是因为后者只能读一次,这样一个DataReader只能对应一个控件,每个控件就要求进行一次数据检索。
    • 当数据的变化不是很频繁(即不要求每次使用数据时都从数据库从新检索它以保证它获得及时的更新)时,最好使用DataSet。DataSet可以保存在一个会话(Session)或者程序变量中,它也可以用System.Web.Caching.Cache类进行缓冲,这样由于降低了从数据库直接检索数据的次数,应用程序的性能会有所提高。
    • 当建立返回检索数据的Web服务时,最好使用DataSet 。由于DataSet是可串行化的,因此它可以作为返回值。而DataReader由于需要连续的数据库连接,因此它不能作为Web服务的返回值。


    牢记这两个数据查询类——这一点很重要。这两种方法所针对的目标截然不同。