.NET 数据访问架构指南(转)

 


Alex Mackman, Chris Brooks, Steve Busby, 和 Ed Jezierski
微软公司
2001年10月

概述:本文提供了在多层.NET应用程序中实施基于ADO.NET的数据访问层的指导原则。其重点是一组通用数据访问任务和方案,并指导你选择最合适的途径和技术(68张打印页)。

目录

简介

如果你在为.NET应用程序设计数据访问层,那么就应该把 Microsoft ADO.NET用作数据访问模型。ADO.NET扩展丰富,并且支持结合松散的数据访问需求、多层Web应用程序及Web服务。通常,它利用许多扩展丰富的对象模型, ADO.NET提供了多种方法用于解决一个特定问题。

本文将指导你选择最合适的数据访问方法,其做法是详细列出大范围的通用数据访问方案,提供运用技巧,并且建议最优实践。本文还回答了其它经常问到的问题:何处最适合存放数据库链接字符串?应如何实现链接存储池?如何处理事务?如何实现分页以允许用户在许多记录中滚动?

注意本文的重点是ADO.NET的使用:利用SQL Server .NETData Provider--随ADO.NET一起提供的两个供应器之一--访问Microsoft SQL Server 2000。本文在合适的地方,将突出显示在你使用OLE DB .NET数据供应器访问其它OLE DB敏感数据源时需要注意的所有差别。

对于利用本文所讨论的指导原则和最优实践所开发的数据访问组件的具体实现,见(Data Access Application Block)数据访问应用程序块。注意,本实现的源代码是可以获得的,并且能直接用于你的.NET应用程序中。

谁应当阅读本文?

本文为希望构建.NET应用程序的应用程序设计师和企业开发人员提供了指导原则。如果你负责设计并开发多层.NET应用程序的数据层,那么请阅读本文。

你首先需要知道什么?

要利用本指南构建.NET应用程序,你必须有利用ActiveX数据对象(ADO)和/或 OLE DB开发数据访问代码的实际经验,及SQL Server经验。你也必须明白如何为.NET平台开发管理代码,并且也必须清楚ADO.NET数据访问模型引入的基本变化。有关.NET开发的更多信息,见http://msdn.microsoft.com/net

ADO.NET简介

ADO.NET是.NET应用程序的数据访问模型。它能用于访问关系型数据库系统,如SQL Server 2000,及很多其它已经配备了OLE DB供应器的数据源。在某种程度上,ADO.NET代表了最新版本的ADO技术。然而,ADO.NET引入了一些重大变化和革新,它们专门用于结构松散的、本质非链接的Web应用程序。关于ADO 与 ADO.NET的比较,见MSDN中的“用于ADO程序员的ADO.NET”一文。

ADO.NET引入的一个重要变化是,用DataTable, DataSet, DataAdapter, 和 DataReader对象的组合代替了ADO Recordset对象。DataTable表示来自一个表的行集合,在这方面它与Recordset类似。DataSet表示DataTable对象的集合,及与其它表绑定在一起的关系和限制。实际上,DataSet是具有内置的扩展标记语言(XML)支持的内存中的关联结构。

DataSet的一个主要特点是,它对底层的数据源一无所知,而这些数据源可能用于对其进行填充。这是一个分离的用于表示数据集合的独立实体,并且它可通过多层应用程序的不同层由一个组件传递到另一组件。它也可作为XML 数据流被序列化,因而非常适合于不同类型平台间的数据传输。ADO.NET使用DataAdapter对象为发送到和来自DataSet及底层数据源的数据建立通道。DataAdapter对象还支持增强的批更新特性,以前这是Recorder的相关功能。

图1显示了完整的DataSet对象模型。


图1 DataSet 对象模型

.NET 数据供应器

ADO.NET 依靠.NET 数据供应器的服务。 它们提供了对底层数据源的访问,包括四个主要对象(Connection, Command, DataReader,及DataAdapter),目前,ADO.NET只发行了两个供应器:

  • SQL Server .NET 数据供应器。这是用于Microsoft SQL Server 7.0及其以后版本数据库的供应器,它优化了对SQL Server的访问,并利用 SQL Server内置的数据转换协议直接与SQL Server通信。
  • 当链接到SQL Server 7.0 或 SQL Server 2000时,总是要使用此供应器。
  • OLE DB .NET 数据供应器。. 这是一个用于管理OLE DB 数据源的供应器。它的效率稍低于SQL Server .NET Data Provider,因为在与数据库通信时,它需通过OLE DB层进行呼叫。注意,此供应器不支持用于开放数据库链接(ODBC),MSDASQL的OLE DB供应器。对于ODBC数据源,应使用ODBC .NET数据供应器。有关与ADO.NET兼容的OLE DB供应器列表,见 。

目前测试版中的其它.NET数据供应器包括:

  • ODBC .NET 数据供应器。目前Beta 1.0版可供下载。它提供了对ODBC驱动器的内置访问,其方式与OLE DB .NET数据供应器提供的对本地OLE DB供应器的访问方式相同。关于ODBC .NET及Beta版下载的更多信息见 .
  • 用于从SQL Server 2000中得到XML的管理供应器。用于SQL Server Web升级2版的XML还包括了专用于从SQL Server 2000中得到XML的管理供应器。关于此升级版本的更多信息,见 .

名称空间组织

与每个.NET数据供应器相关的类型(类,结构,枚举,等等)位于它们各自的名称空间中:

  • System.Data.SqlClient. 包含了 SQL Server .NET 数据供应器类型。
  • System.Data.OleDb. 包含了 OLE DB .NET数据供应器类型。
  • System.Data.Odbc. 包含了ODBC .NET数据供应器类型。
  • System.Data. 包含了独立于供应器的类型,如DataSet及DataTable。

在各自关联的名称空间中,每个供应器都提供了Connection, Command, DataReader, 及 DataAdapter对象的实现。SqlClient实现都有前缀"Sql";而OleDb实现前面都有前缀"OleDb"。例如,Connection对象的 SqlClient实现是SqlConnection。而OleDb实现是OleDbConnection。类似的,DataAdapter对象的两种实现是SqlDataAdapter 和OleDbDataAdapter。

通用编程

如果你很有可能以不同的数据源为目标,并希望将代码从一种数据源移植到另一数据源,那么可以考虑对System.Data名称空间中的IDbConnection, IDbCommand, IDataReader,和IDbDataAdapter接口进行编程。Connection, Command, DataReader, 及 DataAdapter对象的所有实现都必须支持这些接口。

关于实现.NET数据供应器的更多信息,见http://msdn.microsoft.com/library/en-us/cpguide/html/cpconimplementingnetdataprovider.asp.

图2显示了数据访问堆栈及ADO.NET如何与其它数据访问技术,包括ADO和OLE DB,联系起来。该图还显示了ADO.NET模型中的两个管理供应器和主要对象。


图2 数据访问堆栈

关于ADO到ADO.NET的演化,见MSDN杂志2000年11月期的文章“ADO+简介:用于微软.NET框架的数据访问服务”。

存储过程与直接SQL的比较

在本文剩余部分的大部分代码片段中,都使用了SqlCommand对象调用存储过程去执行数据库操作。在一些例子中,你见不到SqlCommand对象,因为存储过程名直接传递给了SqlDataAdapter对象,但这仍将导致SqlCommand对象的创建。

使用存储过程而非SQL语句的原因是:

  • 存储过程通常会使性能增加,因为数据库可以优化过程使用的数据访问计划,并对其进行缓存以备将来重用。
  • 在数据库中,存储过程可分别得到保护。客户可以被给予执行某个存储过程的权限,但无权处理底层的表。
  • 存储过程将导致维护简单,因为在一个已部署组件内,修改存储过程通常要比修改硬编码的SQL语句简单。
  • 存储过程增加了一个从底层的数据库结构中提取出的层。存储过程的客户与存储过程的实现细节及底层结构被隔离开了。
  • 存储过程可以降低网络流量,因为SQL语句可以以批处理的方式执行,而不是从客户端发送多个请求。

属性与构造函数的比较

可以通过构造函数参数或直接设置属性来为ADO.NET对象设置具体的属性值。例如,下面的代码片段在功能上是等同的。

// Use constructor arguments to configure command object
SqlCommand cmd = new SqlCommand( "SELECT * FROM PRODUCTS", conn );

// The above line is functionally equivalent to the following
// three lines which set properties explicitly
sqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM PRODUCTS";

从性能角度来说,两种方法的差别可以忽略,因为设置或获得.NET对象的属性比对COM对象执行类似操作要有效得多。

所作出的选择只是个人爱好和编码风格而已。然而,明确地设置属性的确使代码易于理解(特别是当你不熟悉ADO.NET对象模型时),便于调试。

注意 过去,VB开发人员被建议避免使用"Dim x As New…"结构创建对象。在COM环境中,这些代码将导致COM对象创建过程的“短路”,产生一些奇妙的和不怎么奇妙的错误。然而,在.NET环境中,这已不再是一个问题。

管理数据库链接

数据库链接是一种危险的、昂贵的、有限的资源,特别是在多层Web应用程序中。你必须正确管理你的链接,因为你的方法将极大的影响应用程序的整体升级性。还有,必须仔细考虑在哪儿存放链接字符串。你需要一个可配置的、安全的位置。

在管理数据库链接和链接字符串时,你应当努力:

  • 通过跨多个客户多路复用一池数据库链接来帮助实现应用程序的扩展性。
  • 采用可配置的、高性能的链接池战略。
  • 在访问SQL Server时使用微软Windows操作系统认证。
  • 避免中间层的冒充。
  • 安全地存储链接字符串。
  • 较晚地打开数据库链接,而较早地关闭它们。

本节讨论链接池,并帮你选择合适的链接池战略。其它可选方法也是存在的。本节也将考虑如何管理、存储、控制数据库链接字符串。最后,本节还提供了两个编码方案,使用它们将有助于确保链接已可靠关闭,并返回到链接池中。

链接池

数据库链接池使应用程序能够重用池中的现有链接,而不是重复地建立对数据库的链接。这种技术将极大地增加应用程序的可扩展性,因为有限的数据库链接可以为很多的客户提供服务。此技术也将提高性能,因为能够避免用于建立新链接的巨大时间。

数据访问技术,如ODBC和OLE DB,提供了多种形式的链接池,它们可配置到不同级别上。这两种方式对数据库客户端应用程序来说都是透明的。OLE DB链接池经常被称为会话或资源池。

关于微软数据访问组件(MDAC)中池的一般讨论,见http://msdn.microsoft.com/library/en-us/dnmdac/html/pooling2.asp

ADO.NET数据供应器提供了透明的链接池,每种链接池的确切机制对每种供应器来说是不同的。本节讨论的链接池是关于:

用SQL Server .NET 数据供应器池化

如果正在使用SQL Server .NET数据供应器,那么就可使用该供应器提供的链接池化支持特性。它是由供应器在管理代码内内置实现的对事务敏感的高效机制。每个过程都将创建池,并且直到过程结束,池才被取消。

你可以透明地使用此种链接池,但应当清楚池是如何被管理的,并要知道可以用哪些选项来调整链接池。

如何配置SQL Server .NET数据供应器链接池

可以使用一组名称-值对以链接字符串的形式配置链接池。例如,可以配置池是否有效(默认是有效的),池的最大、最小容量,用于打开链接的排队请示被阻断的时间。下面的示例字符串配置了池的最大和最小容量。

"Server=(local); Integrated Security=SSPI; Database=Northwind; 
Max Pool Size=75; Min Pool Size=5"

当链接打开,池被创建时,多个链接增加到池中以使链接数满足所配置的最小值。此后,链接就能增加到池中,直到配置的最大池计数。当达到最大计数时,打开新链接的请求将排队一段可配置的时间。

选择池容量

能建立最大极限对于管理几千用户同时发出请求的大型系统来说是非常重要的。你需要监视链接池及应用程序的性能,以确定系统的最优池容量。最优容量还要依赖于运行SQL Server的硬件。

在开发期间,也许需要减小默认的最大池容量(目前是100)以帮助查找链接泄漏。

如果设立了最小池容量,那么当池最初被填充以达到该值时,会导致一些性能损失,尽管最初链接的几个客户会从中受益。注意,创建新链接的过程被序列化了,这就意味着当池最初被填充时,服务器无法处理同时发生的请求。

关于监视链接池的更多信息,见本文监视链接池一节。关于链接池链接字符串关键字的完整列表,见http://msdn.microsoft.com/library/en-us/cpguide/html/cpconconnectionpoolingforsqlservernetdataprovider.asp

更多信息

在使用SQL Server .NET数据供应器链接池时,必须清楚:

  • 链接是通过对链接字符串精确匹配的法则被池化的。池化机制对名称-值对间的空格敏感。例如,下面的两个链接字符串将生成单独的池,因为第二个字符串包含了一个额外的空字符。
    SqlConnection conn = new SqlConnection(
             "Integrated Security=SSPI;Database=Northwind");
    conn.Open(); // Pool A is created
    
    SqlConmection conn = new SqlConnection(
             "Integrated Security=SSPI ; Database=Northwind");
    conn.Open(); // Pool B is created (extra spaces in string)
    
  • 在.NET框架Beta版中,当在调试器中运行时,链接池化总是失效了。在调试器外,对调试版和发行版,链接池都能正常运作。.NET框架的最终发行版(RTM)取消了这种限制,链接池在所有情况下都能运行。
  • 链接池被划分为了多个特定于事务的池和一个用于目前没有列在事务中的多个链接的池。对于与特定事务上下文相关的线程,将从(包含了与事务建立的链接的)合适的池中返回链接。这使得使用已建立的链接成为透明过程。

    用OLE DB .NET数据供应器池化

    OLE DB .NET数据供应器利用OLE DB资源池化的底层服务将链接存储到池中。很多方法可用于配置资源池化:

    • 可以使用链接字符串来配置、使能资源池化或使其使失效。
    • 可以使用注册表。
    • 可以通过程序来配置资源池化。

    为了避开与注册表相关的部署问题,应避免使用注册表配置OLE DB资源池化。

    关于OLE DB 资源池化的更多细节,见MSDN中“OLE DB程序员参考”一书的第19章:OLE DB服务中的资源池化部分。

    用池化对象管理链接池化

    作为Windows DNA开发人员,建议你使OLE DB资源池化和/或ODBC链接池化失效,并把COM+对象池化用作将数据库链接存储到池中的技术。这样做主要出于两个原因:

    • 池容量和极限可以(在COM+目录)被明确配置。
    • 性能提高了。池化对象的方法可以成倍的胜过固有池化。

    然而,由于SQL Server .NET数据供应器内置地使用池化,所以(在使用此供应器时)你不再需要开发自己的对象池化机制。这样就可以避免手工事务征募带来的复杂性。

    如果正在使用OLE DB .NET数据供应器,那么考虑COM+对象池化以从高级配置和改进的性能中受益。如果你为此目的开发一个池化对象,那么必须使用OLE DB资源池化和自动事务征募失效(例如,通过将“OLE DB Services=-4”包含进链接字符串中)。必须在池化对象的实现中处理事务征募。

    监视链接池化

    要监视应用程序对链接池化的应用情况,可以使用随SQL Server发行的Profiler工具,或随微软Windows 2000发行的性能监视器。

    要利用SQL Server Profiler 监视链接池化,操作如下:

    1. 单击开始,指向程序,指向Microsoft SQL Server,然后单击Profiler运行Profiler。
    2. 文件菜单中,指向新建,然后单击跟踪
    3. 提供链接内容,然后单击确定
    4. 跟踪属性对话框中,单击事件标签。
    5. 已选事件类别列表中,确保审核登录审核登出事件显示在安全审核下面。
    6. 单击运行开始跟踪。在链接建立时,将会看到审核登录事件;在链接关闭时看到审核登出事件。

    要通过性能监视器监视链接池化,操作如下:

    1. 单击开始,指向程序,指向管理工具,然后单击性能运行性能监视器。
    2. 在图表背景中右击,然后单击增加计数器。
    3. 在性能对象下拉列表框中,单击SQL Server:通用统计。
    4. 在出现的列表中,单击用户链接。
    5. 单击增加,然后单击关闭。

    注意 .NET框架的RTM版本将另外包含一组ADO .NET性能计数器(这些计数器能与性能监视器结合起来使用),这些计数器用于为SQL Server .NET数据供应器监视并积累链接池化状态。

    管理安全性

    尽管数据库链接池化提高了应用程序的整体扩展性,这也意味着你不再能够在数据库端管理安全性。这是因为为了支持链接池化,链接字符串必须是相同的。如果需要跟踪每个用户的数据库操作,那么考虑为每个操作增加一个参数,通过这个参数就可以传递用户身份,手工将用户活动记入数据库。

    使用Windows 认证

    在链接到SQL Server时,应当使用Windows认证,因为它提供了许多优点:

    • 安全性易于管理,因为使用了单一(Windows)安全模型而不是分散的SQL Server安全模型。
    • 避免了在链接字符串中嵌入用户名和密码。
    • 用户名和密码不是以明文方式在网络中传输的。
    • 通过密码过期期限,最小长度,多次无效登录请求后帐号锁定提高了登录的安全性。

    性能

    .NETBeta 2版的性能测试表明,使用Windows认证与使用SQL Server认证相比,要花费更多的时间才能打开池化的数据库链接。然而,尽管Windows认证的成本较高,但与执行一个命令或存储过程所花费的时间相比,其(引起的)性能损失相对来说并不重要。结果,上面所列出的Windows认证的优点通常会稍微超过性能损失。

    同样,当打开一个池化链接时,在.NET框架的RTM版本中,Windows认证与SQL Server认证的差别有望变得更不明显。

    避免在中间层中冒充

    Windows认证需要访问数据库的Windows帐号。虽然看上去在中间层中使用冒充更符合逻辑,但必须避免这样做,因为损害链接池化并对应用程序的扩展性产生严重影响。

    为了解决这个问题,考虑对有限的Windows帐号(而不是被认证的负责人)实施冒充,每个帐号代表一个特定的角色。

    例如,可以考虑下面的方法:

    • 创建两个Windows帐号,一个用于读操作,一个用于写操作(也可以用单独的帐号映射针对特定应用程序的角色。例如,可以为互联网用户使用一个帐号,而为内部操作员和/或管理员使用另外的帐号)。
    • 将每个帐号映射到一个SQL Server数据库角色,然后为每个角色设置所需的数据库权限。
    • 在数据访问层中使用应用程序逻辑确定执行数据库操作时,哪个Windows帐号需要冒充。

    注意 每个帐号必须是同一域或信任域中在Internet信息服务(IIS)和SQL Server中存在的域帐号;也可以是在每台计算机上创建(具有相同用户名和密码)的匹配帐号。

    为网络库使用TCP/IP

    SQL Server 7.0及其以后版本支持用于所有网络库的Windows认证。使用TCP/IP可以获得配置、性能及扩展性优点。关于使用TCP/IP的更多信息,见本文通过防火墙建立链接 一节。

    存储链接字符串

    有多种方法可存储链接字符串,每种方法具有不同程度的灵活性和安全性。尽管在源代码中对字符串进行硬编码提供了最优性能,但文件系统缓存确保了与在文凭系统外部存储字符串相关的性能损失可被忽略。实际上外部链接字符串(允许管理员进行配置)所提供的附加灵活性在任何情况下都是受欢迎的。

    选择存储链接字符串的方法时,首先要考虑的两个重要因素是配置的安全性与简易性,其次是性能。

    可以选择将数据库链接字符串存储在下列位置:

    使用Windows认证访问SQL Server,就可以避免在链接字符串存储用户名和密码。如果 安全需求要求更严格的方式,那么就考虑以加密格式存储链接字符串。

    对于ASP.NET Web应用程序,以加密格式将链接字符串存储在Web.config文件中是一种安全而可配置的解决方案。

    注意,在链接字符串中将Persist Security Info命名值设置为假,就可以阻止利用SqlConnection 或OleDbConnection对象的ConnectionString属性返回对安全敏感的内容,如密码。

    下面几个小节讨论了如何用这些方法存储链接字符串,并说明了相对的优点和缺点。这使你能根据特定的应用程序环境作出相应的的选择。

    使用XML应用程序配置文件

    可以使用元素appSettings将数据库链接字符串存储在应用程序配置文件的定制设置部分。该元素支持任意关键字-值对,如下面的代码片段所示:

    <configuration>
     <appSettings>
      <add key="DBConnStr"
         value="server=(local);Integrated Security=SSPI;database=northwind"/>
     </appSettings>
    </configuration>
    

    注意:appSettings元素现在在configuration元素下面,并且不能直接出现在system.web下面。

    优点

    • 易于部署。通过常规.NET xcopy部署,链接字符串随配置文件一起被部署。
    • 通过程序易于访问。ConfigurationSettings类的AppSettings属性使得在运行时读取数据库链接字符串更为简单。
    • 支持动态更新(仅限于ASP.NET)。如果管理员更新了Web.config文件中的链接字符串,那么下次在字符串被访问时所作出的变化生效,这对一个无状态的组件来说,就象客户再次利用组件作出了数据访问请求一样。

    缺点

    安全性。尽管ASP.NET Internet 服务器应用程序编程接口(ISAPI)DLL阻止了客户直接访问带.config扩展名的文件,并且NTFS文件系统权限也用于进一步限制访问,但你可能仍希望避免以明文方式将这些内容存储在前端的Web服务器上。要增加安全性,需将链接字符串以加密格式存储在配置文件中。

    更多信息

    利用System.Configuration.ConfigurationSettings类的AppSettings静态属性,可以获取应用程序的定制设置。如下面的代码片段所示,此处假定先前示例的定置关键字为DBConnStr。

    using System.Configuration;
    private string GetDBaseConnectionString()
    {
      return ConfigurationSettings.AppSettings["DBConnStr"];
    }

    关于配置.NET 框架应用程序的更多信息,见

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值