Scott Howlett 和 Darryl Jennings 本文假设读者熟悉 XML、ASP 和 ADO。下载本文提供的代码:SQLXML.exe (516KB)
摘要 将 XML 用于数据访问使您可以将数据从表示形式中分离出来,并可以提高可重用性、可扩展性和人工的分配。XML 还有一个简化的数据模型,可以使测试更容易。本文提供并比较了五种数据访问方法,这些方法使用各种技术,包括 ASP 和 ADO、XSLT 以及 DirectXML。构建解决方案后,根据它们的速度和效率对它们进行比较。
假设您正在设计数据驱动的 Internet 应用程序。您要从数据库获取数据,以便在 Web 上进行展示。另外,您想要确保此解决方案架构良好,但又不将性能作为主要考虑事项。您非常希望用于下游方向(从数据库到浏览器)的解决方案很好地向上游方向(从浏览器到数据库)扩展。
本文是 MSDN_ Magazine 2000 年 9 月一期中 "aspx" target="_blank">Beyond ASP:XML and XSL-based Solutions Simplify Your Data Presentation Layer" 一文的后续内容。在讨论为上述方案实现的各种解决方案之前,我们将首先快速回顾一下那篇文章,然后阐明一些根据我们前 10 个月以来收到的大量反馈的主题。
接下来,将概述 SQL Server™ 2000 对 XML 的支持,焦点集中在使用 XSD 映射架构的模板和更新图上。然后,将在实践中介绍实现这些想法的示例应用程序。基本上,使用五种不同的方法生成同一示例应用程序,每次使用 ASP、ADO、XML、XSLT、SQL Server 2000 和 .NET 技术的不同组合。最后,还包含了基准测试编号,以解决开发人员使用基于 XML 的结构时有关性能和可伸缩性方面所关心的问题。
回顾
过去,我们将 XML 和 XSL 用于所有类型的解决方案,从大型企业应用程序一直到五天或十天的小项目。我们发现其中的大多数 XML 资源实际上集中在作为企业技术的 XML 上,因此大多数站点仍在使用传统 ASP 方法进行构建,此方法自从第一次从早期的 Microsoft_ Internet Information Server (IIS) 3.0 中引入以来基本上未做任何更改。
从 "Beyond ASP" 文章发表的那一年之后,情况有了很大变化。最值得注意的是,在 2000 年 10 月发布了 MSXML 3.0(支持 W3C 标准 XSLT),接下来发布了 .NET,然后发布了 SQL Server 2000,而且很快又出现了两个增强其 XML 功能的 Web 发布版本。简而言之,这些新技术增强了用于几乎所有基于 Internet 的应用程序的以 XML 为中心的方法。事实上,为了优化对基于 Microsoft .NET 的服务器的开发,必须将 XML 作为结构的中心予以考虑。
以 XML 为中心的 Internet 开发方法已经成为主流。同时,数据库的接口正从 SQL 向双向 XML 转变,因此可能提供很多新的强大功能。在这里,我们将主要讨论新兴技术如何将此设计概念变为现实。
另一个需要注意之处—我们在示例代码上花费了大量时间(甚至提供了帮助设置内容的自述文件),所以请对它进行尝试。在本文顶部的链接中可以找到本文的所有代码。
使用 XML 的九个原因
XML 促进了表示形式与数据的分离,提高了可重用性、可扩展性和人工的分配。另外,它有一个简化的数据模型,允许一个位置有一个事务,并帮助简化测试。还因为 XML 可与旧式系统集成在一起(将来一定继续发展的趋势)而受到越来越多的欢迎。
在这里,我们将集中讨论其中的三点:
•1. 人工的分配。不同的小组成员有不同的技能,结构设计良好的解决方案可以充分发挥每个小组成员的技能水平。要有效地执行此任务,必须从前端开发人员处抽象出关系数据模型。
•2. 一个位置一个事务。XML 在单一可移植实体中提供完整事务和复杂数据集。此可移植数据容器是对记录集或其他专用数据格式的跨越。
•3. 展望未来。Microsoft 已经将 XML 采纳为 .NET 平台的关键技术之一,我们将在检验 .NET 企业级服务器时讨论 .NET 平台。
将根据这三个标准对五个示例应用程序中的每一个进行测量。
XML 和 XSLT
认识到下面这一点很重要:当使用 XSLT 时,没有交叉浏览器问题—如果客户端不支持 XSLT,始终可以在服务器上执行转换。另外,您会发现 XSLT 生成的 HTML 比您通过其他方法获得的 HTML 更符合 HTML 标准。
您还会发现,在生成复杂的 HTML 页面方面,XSLT 的能力与过程代码一样强。另外,对于无数例外中的那些内容,可以始终采取调出到脚本的方法。作为 XSLT 能力的示例,可将 EDI 文档转换为 XML 的 BizTalk™ Mapper 使用底层的 XSLT。熟悉它之后,XSLT 会比带有嵌入 HTML 的过程代码更模块化(因而更可维护)。
使用 XML,不会有磁盘输入/输出问题。由于所有 XML 文档加载到内存中,使用 XML/XSLT 方法不会比其他方法产生更多的磁盘 I/O 操作。开发人员已明确关注使用脚本代码(而不是已编译的 COM 对象)时的性能。坦率地讲,我们使用脚本生成示例应用程序是因为它们更便于用户在他们自己的系统上下载、安装和运行。在任何事件中,脚本代码与 Windows_ 2000 上基于 Visual Basic_ 的 COM 代码之间都会有可忽略的性能差异。不相信我们吗?请参阅 asp" target="_blank">Architecture Decisions for Dynamic Web Applications:Performance, Scalability, and Reliability。
开发人员还关注使用 RecordsetToXMLDoc 函数时的性能,此函数通过在记录中进行循环以将 ADO 记录集转换为 XML 文档来生成 XML。为什么不应该使用 ADODB.Recordset.Save adPersistXML(它生成二维 XML 结构)?很显然,它的优点只比直接使用记录集多一点,况且您不能对生成的 XML 结构进行控制。XML 的强大功能在于它可为任意深的分层数据建模的能力—将您自己限制在二维层次结构(使用 adPersistXML 导致的结果)会极大降低 XML 的功能。
另一个性能考虑集中在 XML 解决方案公开的执行层数量上。如果允许,通过将记录集手动转换为 XML,可以添加另一层。但是,软件是完全抽象的,这通常意味着引入另一层。您很快会看到,使用在 SQL Server 2000 中引入的功能,可以获得所有抽象好处(不用引入另一层),并且性能会同时获得很大提高。
像任何新技术一样,需要花一些时间熟悉 XML 和 XSLT。应该记住,迟早您必须学会 XML—只要随意扫一眼 BizTalk 和 .NET,您便会在某一处看到 Microsoft 已经采用了 XML。sqlserver/art/figures2.html" target="_blank">图 1 是您需要了解的一些术语的方便参考指南。
SQL Server 2000 的 XML 功能
许多开发人员指出(事实上确实如此)从记录集到 XML 的转换会引入另一个执行层。即使这样,我们仍会在 XML/XSLT 设计模式中发现许多好处。SQL Server 2000 附带了本机 XML 支持,而且 SQL Server 2000 Web Release 2 Beta 1 (WR2b1) 甚至还添加了更多的基于 XML 的功能,从而避免了层的问题。现在,可以获得 XML 的所有好处,不用引入额外的执行层,进而避免了因引入执行层而产生的复杂性。
Microsoft 的开发人员在可通过 HTTP 访问 SQL Server 2000 的 XML 功能方面做了很多工作。此访问方法需要在服务器上配置虚拟目录,有关详细信息,将在示例应用程序的安装说明中进行解释。从 Web Release 2 Beta 1 起,还可以通过使用 ADO 命令、流和连接对象,以编程方式使用 SQL Server 2000 XML 功能。为了更好地了解如何同时使用 HTTP 和编程访问方法以及它们的执行方式,我们使用它们开发了第三方示例应用程序。出乎我们的意料,基于 HTTP 的访问远比通过 ADO 的编程执行快(请参阅本文结尾处关于性能的一节)。
有两种不同的方法可用来根据 SQL 数据库的内容生成 XML 视图。您将会看到,生成的 XML 可以基于一个或多个表,而且可以为任意深。第一个方法使用 SQL Server 2000 扩展的 SELECT 语句语法,第二个方法利用对 XPath 查询和映射架构的支持。SQL 扩展功能可以与模板一起使用,也可以不与其一起使用,并且不需要映射架构。相反,XPath 查询必须在模板内使用,而且此模板必须指定映射架构。
SQL 查询扩展功能
SELECT 语句的语法已经进行了扩展,以支持使用新的 FOR XML 子句直接从 SQL Server 2000 检索 XML 文档。FOR XML 子句有三个使用模式,每一个模式都允许对其生成的 XML 文档的外观进行不同程度的控制。这些模式为 Raw、Auto 和 Explicit。对于如何使用这些方法的完整解释已超出了本文范围,但 SQL Server 2000 文档中给出了很好的说明。SQL 查询扩展功能的一个很大的限制是它们不利于使用更新图(更新图需要映射架构)。
Raw 模式(用于 XML RAW)生成一个 XML 文档,此文档与 ADODB.Recordset.Save adPersistXML 方法生成的文档类似(有关此方法的更多信息,请参阅 ADO 文档)。这意味着生成的 XML 文档将有一个较浅的层次结构,并且只会像传统记录集那样工作,而不能利用使用 XML 时可用的任意复杂的树结构。
Auto 模式(用于 XML AUTO)能够根据表的数量和顺序以及 SELECT 语句的 FROM 子句中使用的联接策略,自动生成 XML 文档。各种联接风格的创新使用有助于生成许多简单的 XML 文档结构,但是当尝试发布带有复杂结构的文档时其局限性会很快暴露出来。
Explicit 模式可用于对生成的 XML 文档的性能进行完全的控制,因此使用起来更复杂一些。基本上,您获得了对 XML 文档的完全控制,但同时失去了映射方案的好处。
请注意,FOR XML 子句有一个称为 XMLData 的选项,如果指定了此选项,则会包括一个自动生成的带有 XML 视图的 XDR 方案内联,但它不是映射方案。
SQL 模板
如上所述,通过指定使用了 SQL 查询扩展 FOR XML 的SELECT 语句,或者通过指定映射方案和 XPath 查询,可以使用模板。我们认为将模板与 XSD 映射方案和 XPath 查询一起使用是从 SQL Server 2000 直接获取基于 XML 的数据的最强大机制。
您可以回想一下,如果 XSD 方案包括 SQL Server 2000 需要的所有必需的批注,以便处理从关系数据存储到 XML 视图的映射,则它是映射方案。特别地,必须使用 sql:relationship 标记来明确定义外键关系。这些关系必须包括在 xsd:annotation 标记中,以便使映射方案符合 XSD。图 2 是这些批注的示例。
图 3 显示了用于示例应用程序的 XSD 映射方案,而不显示图 2 中的批注以便节省空间。(如果还不熟悉 XSD 方案,可以参阅 http://www.w3.org/TR/xmlschema-0。)注意关系数据存储中的表和列如何使用属性映射到 XML 元素:sql:relation 映射表,sql:key-fields 映射主键,sql:field 映射列,sql:relationship 映射键关系。
由于许多原因,SQL 扩展功能首选使用映射方案和模板。例如,无论如何,您都需要映射方案以使用更新图,且复杂映射方案比 FOR XML Explicit 等效方案更容易编写。另外,使用 SQL 查询扩展功能需要您编写 SELECT 语句,而映射方案的添加则不需要。您还会发现映射方案对 .NET 和 BizTalk 方案都非常有用。最后,XML 最佳实施规定了方案的使用。
另外,XSD 首选级别高于 XDR,因为 XSD 是 W3C 标准。此模板生成使用 XSD 映射方案的数据的 XML 视图。
<persons xmlns:sql="urn:schemas=microsoft=com:xml=sql"> <sql:xpath-query mapping-schema=:.\persons.xsd:> person </sql:xpath-query> </persons> Visual Studio .NET 设计器将为您显示 XSD 方案 (sqlxml\persons.xsd)。前面的模板还生成了如图 4 所示的 XML 数据。
SQL 更新图
如果对通过符合 XSD 映射方案的可自定义形式从 SQL 数据库提取数据并不感兴趣,请记住,您还可以使用更新图。更新图使您可以提供要映射回数据库的符合方案的 XML 文档,而不是编写自己的分解代码和插入代码。
在第二个 SQL Server 2000 Web 发布版本中包括了对更新图的支持。它们使用户可以根据 XML 文档及其相应映射方案的内容插入、更新和删除关系数据库信息。这使 SQL Server 2000 可以成为双向 XML 库!用户现在可以用 XML 文档的形式请求信息,进行更改,添加和删除信息,然后将它以 XML 格式发回,让它在关系数据库中正确映射和存储。
更新图很容易使用(虽然此时错误消息通常很不明确)。在更新图中,所有工作都在 <sync> 块之间完成。可以包括任意数量的 <sync> 块,在它们中所做的所有更改都是事务性的。每个事务可以包含任意数量的 before 块和 after 块。
这些块的功能非常直观。<before> 块包含现有 XML 视图的一部分,<after>块是当进行更改时您想要这部分视图所呈现出的外观。根据 <before> 与 <after> 块之间的差异以及您提供的映射方案,为您完成所有插入、更新和删除工作。(有关更新图的使用,请参阅随第二个 Web 发布版本提供的 "XML for SQL" 文档)。请注意,更新图可以影响多个行和多个表。图 5 是在 pubs 数据库中修改数据的更新图的示例。
更新图如何处理对数据库的并发访问,即避免用户 B 的更新覆盖用户 A 的更新?答案在于更新图对乐观锁定策略的灵活使用。基本上,SQL Server 2000 会将更新图中的 <before> 块的内容与数据库中已有的内容进行比较。如果数据不同,由于检测到乐观锁定,此操作将不继续。
您在 <before> 块中包含的信息越多,冲突检测将越严格。通过只包括键字段,将始终应用您的更新,除非键字段不再存在。如果您下载本文的示例代码,则会发现示例更新图和 ADO 执行代码,该执行代码只包括 <before> 块中的主键。
所以,现在我们有一个机制,使用模板和 XSD 映射方案直接从 SQL Server 2000 获取 XML。我们还有一个机制,使用更新图和相同的 XSD 映射方案将 XML 直接获取到 SQL Server 2000 中。所有这些操作甚至连一行 SQL 都不用写入。很酷。
示例应用程序
下一步,让我们直接跳到示例应用程序,以便您可以了解正在生成的内容。我们决定从 pubs 数据库展示作者及其相关书籍的显示。 图 6 显示了数据的生成视图。数据的视图有些复杂,它包括某种服务器生成的 DHTML,该 DHTML 允许根据需要展开或折叠每个作者的书籍。
图 6 DHTML 只读视图
我们以如图 7 所示的五个不同方法生成示例页面。将在下面的几节中描述这些解决方案/示例应用程序中的每一个。
解决方案 1
使用 ASP 和 ADO 生成此页面时所需的代码(图 8 中给出了概念性显示)看起来应该非常熟悉。
可以在 straightasp.asp 中找到完整的代码列表, 图 9 显示了所需代码的一部分。很明显,数据访问代码无奈地与表示形式代码缠绕在一起。图 10 显示此解决方案对各种标准排列得多么出色。
解决方案 2
在称为解决方案 2(图 11 中给出了概念性定义)的方法中,我们像解决方案 1 中一样对数据库进行了相同的调用,但在执行时并未生成 HTML,而是得到了一个函数调用 (GetXMLFromDB) 中的所有数据,然后应用了 XSLT 样式表。在此情况下,数据已经从完全从任何表示形式格式删除。 图 12 显示了从数据库生成 XML 所必需的代码。
图 11 #2
2000 年 11 月的文章中包含了 RecordsetToXMLDoc 函数。可以在代码下载中的 xml\xmlutil2.asp 文件中找到此函数的更新版本。拥有数据后,进行转换非常简单。图 13 显示了执行转换所需的代码。
您会注意到,基于查询字符串中的值,有三个不同的已执行转换。第一个使用 defaultss.xsl(它显示了原始 XML)进行转换。TransformXML 与 TransformXML2 之间的区别在于 TransformXML2 使用在应用程序变量中存储的缓存的样式表(通过 XSLTemplate 对象)。如果您想要使用 XSLTemplate,从阅读文章 "Inside MSXML3 Performance" 入手进行学习是非常理想的,该文还讨论了此方法如何改善性能。在 inc\xmlutil2.asp(在下载中)中,可以找到函数 TransformXML 和 TransformXML2 的代码。图 14 中总结了解决方案 2。
解决方案 3
解决方案 3(图 15 中给出了概念性显示)看起来与最后一个解决方案很相似,但我们使用 SQL Server 2000 的 XML 功能,而并不手工生成 XML。“SQL Server 2000 的 XML 功能”一节详细解释了此过程,但我们已做的是使用 XSD 方案创建数据的视图。使用此视图,我们指定了 XPath 表达式以提取想要的数据。 图 16 显示了如何使用 SQL Server 2000 WR2b1 附带的 SQLXMLOLEDB 提供程序以编程方式完成此操作。
图 15 #3
可以使用 ADO(通过 SQXMLOLEDB 提供程序)或使用 SQL Server 2000 基于 HTTP 的访问机制以编程方式执行 SQL 模板。此解决方案同时展示了使用同一模板的两个执行选项,以方便对这两者进行比较。基于 HTTP 的访问并不比程序简单,但它速度更快(请参阅本文结尾关于性能的一节)。
ShowAuthorsView 的代码与解决方案 2 中的代码几乎完全相同,但是添加了对基于 HTTP 的数据访问的支持。另外,还添加了对要在模板中使用的不同 XPath 表达式的支持。图 17 显示应用了 XPath 筛选器(此筛选器只能显示协定值为零的作者)的示例应用程序。
使用 XPath 进行筛选
XPath 查询并不始终按我们期望的方式工作(还记得测试软件吗?)。 这里是当执行 XPath 查询时找到的内容。首先,尝试根据不是立即子级的子节点进行筛选的 XPath 表达式将失败 (person[books/book/title_id='PS3333']),并显示错误 "Xpath:an unexpected internal error occurred"(Xpath:发生了意外内部错误)。其次,尝试根据标有 sql:is-constant 的节点所包含的子级进行筛选的 XPath 表达式(例如,person[address/state='CA'])会失败,并显示错误 "The column prefix '_Q1G' does not match with a table name or alias name used in the query."(列前缀 '_Q1G' 与查询中使用的表名或别名不匹配)。
令人期待的是,当发布 WR2b1 for SQL Server 2000 时,我们 将能够使用大量的 XPath 表达式,例如:person[books/book/price > 10],表示编写书籍的所有人,书籍的销售价格超过 10 美元;person[books/book/publisher/location/country='USA'],表示编辑书籍的所有人,书籍的出版商在美国。有关解决方案 3 的分级总结,请参阅图 18。
解决方案 4
解决方案 4(图 19 中给出了模型)与解决方案 3 的工作方式几乎完全相同,不同之处是使用 .NET XML WebControl 来进行转换。
图 19 #4
我们在 Page_Load 方法(来自 dotnettransform.aspx.cs)中只需写四行代码,以加载源 XML 文档(使用基于 SQL Server 2000 HTTP 的 XML 访问)和样式表。
private void Page_Load(object sender, System.EventArgs e) { // Put user code to initialize the page here XmlDocument doc = new XmlDocument(); doc.Load("http://localhost/pubs/templates/alldata.xml"); ctlXML.Document = doc; ctlXML.TransformSource = "xsl\\authors3.xsl"; }
此解决方案并不需要 inc\xmlutil.asp 中的代码,因此,使用 .NET 执行转换不需要 DOM 知识。 图 20 总结了解决方案 4。
解决方案 5
对于解决方案 5(图 21 给出了概述),我们曾想过使用 .NET 中的 DataGrid 生成数据视图,以查看在不写入任何代码(C# 或 XSLT)的情况下可以获取何种功能。
图 21 #5
很明显,生成与解决方案 1 到 4 的格式完全相同的数据视图超出了本文的范围。但是,生成作者的简单视图(不使用客户端的 DHTML)确实是很简单的练习。不用写任何代码,即可完成几乎所有内容!下面是操作步骤:
•1. 首先,使用前面提到的 XSD 架构,通过右键单击 Project | Add Component | Data Set 创建新的数据集类。这会创建新的 XSD 文件和 Visual Studio 自动生成的底层 CS 文件。然后,将架构(是通过手工创建的)粘贴到 XSD 文件中。您也可以选择使用 XML 设计器创建 XSD 文件。
•2. 下一步,将数据集组件从工具框拖动到页面上。这会打开一个向导,可以在其中根据步骤 1 中创建的数据集类创建分类的数据集。您可以在图 22 中的代码中看到,我们调用数据集 dsPersons 和更新的 Page_Load 事件处理程序,以便使用 HTTP 从 SQL Server 2000 检索数据。
•3. 从那里,我们通过右键单击 Datagrid | Property Builder 将 DataGrid 组件从工具箱拖动到了 ASPX 页面。我们将 dsPersons 选作数据源,将人选作数据成员。
•4. 接下来,我们使用了属性生成器来选择要显示的列。
•5. 从那里,我们在属性生成器中配置了“分页”、“格式”和“边框”区域。我们为 OnPageIndexChange 事件添加了事件处理程序(通过将属性 OnPageIndexChanged="dgperson_PageIndexChanged" 添加到 .aspx 文件中的 <asp:DataGrid> 标记)。下面的代码来自 dotnetgrid.aspx.cs,显示了要更改页面的服务器端实现。
public void dgperson_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e) { dgperson.CurrentPageIndex = e.NewPageIndex; dgperson.DataBind(); }
在一天工作的结尾,生成一个数据视图,此视图作为生成与解决方案 1 到 4 中相似的视图的开始点(请参阅图 23)。.NET 遵守大量使用基于 XML 的数据集的约定。 图 24 总结了解决方案 5。
图 23 .NET DataGrid
图 23 .NET DataGrid
性能
出于全面考虑,我们对五个解决方案进行了基准测试,以比较每个方法的性能。请注意,不应该将解决方案 5 与其他解决方案相比较,因为它们的数据视图不同。
测试是使用 Homer(Microsoft 的加载测试应用程序),针对运行 Windows 2000 Server、SQL Server 2000 Web Release 2 Beta 1 和 .NET Framework Beta 2 的服务器运行的。Homer 在 Microsoft Access .mdb 文件中存储其配置信息。示例代码 zip 文件中已经包括了 Homer .mdb 文件,所以您可以将它打开,对您自己的各种配置的每一个进行基准测试。
服务器是 Dell Dimension XPST500,550MHz,256MB 的 RAM。Homer 在单独的工作站上运行。请特别注意图 25 中最后一列中显示的相对性能(与 ASP/ADO 方法比较)。
请看一看使用基于 HTTP 的数据访问和 XSLT(解决方案 3)时令人激动的 11.1 倍的性能提高,使用基于 HTTP 的数据访问和 .NET Transform(解决方案 4)时的性能提高几乎达九倍。虽然这些统计数字并不完全科学,但它显示了 SQL Server 2000 和 .NET 的惊人性能。另请注意,使用过分单纯化的缓存 XSLT 机制并不始终能提高性能。
小结
在这个以 Internet 为中心的时代里,XML 是否将继续扮演重要角色已经没有太多疑问。Microsoft 拥有完整的基于 XML 的产品,从现有已发布的产品(例如,BizTalk 和 SQL Server 2000)到测试产品(例如,.NET)。对软件架构师的挑战是,如何在他们的应用程序中通过使用 XML 而充分利用这些服务器产品。
使用 XSD 映射架构使基于 XML 的数据能够流入和流出 SQL Server 2000 是非常有用的。通过使用 XSD,您将可以立即移植到 .NET,并可以使用 W3C 行业标准。同时,您还会认识到使用 XSLT 和基于 HTTP 的数据访问时的最大性能。
有关相关文章,请参阅:
aspx" target="_blank">Beyond ASP:XML and XSL-based Solutions Simplify Your Data Presentation Layer
A Survey of Microsoft SQL Server 2000 XML Features有关相关文章,请参阅:
A Guide to XML and its Technologies
Inside MSXML3 Performance
Scott Howlett 和 Darryl Jennings 是 imason Inc. 的咨询顾问,该公司是一个 Internet 咨询公司,其业务主要是为生成“企业对企业 (B2B)”和“业务部门 (LOB)”应用程序的公司进行旧式集成。如果希望与他们联系,请将电子邮件发送至 [email protected] 和 [email protected]。