使用 ODBC
本节提供 Oracle 和 SQL Server 使用 ODBC 的方式的信息,以及使用 ODBC 开发和迁移应用程序的信息。
将应用程序代码从 Oracle 转换到 SQL Server 时,请使用下面的过程:
如果应用程序用 Oracle Pro*C 或 Oracle 调用接口 (OCI) 写成,请考虑将应用程序转换为 ODBC。
了解 SQL Server 默认结果集和游标选项,并选择对应用程序最有效的提取策略。
如必要,将 Oracle ODBC SQL 数据类型重新映射到 SQL Server ODBC SQL 数据类型。
使用 ODBC Extended SQL 扩展,创建通用的 SQL 语句。
确定 SQL Server 应用程序是否需要手动提交模式。
测试应用程序的性能,并在需要时修改程序。
Microsoft 提供 16 位和 32 位版本的 ODBC SQL Server 驱动程序。32 位的 ODBC SQL Server 驱动程序是线程安全的。驱动程序将多个线程共享的访问串行送到共享的语句句柄 (hstmt),连接句柄 (hdbc) 和环境句柄 (henv)。即使程序使用多个线程时,ODBC 程序仍负责将语句和连接空间中的操作保持为正确的顺序。
因为 Oracle ODBC 驱动程序可由多个可能的厂商之一提供,对于体系结构和操作,就会有许多可能的方案。必须与厂商联系,确保 ODBC 驱动程序能够满足您的应用程序的需要。
在大多数情况下,Oracle ODBC 驱动程序使用 SQL*Net,与 Oracle RDBMS 连接。与 Personal Oracle 连接时,可以不使用 SQL*Net。
下图给出了 32 位环境的应用程序/驱动程序体系结构。
“形式-实在转换”一词是指一个函数调用,它是一个特殊处理,在 16 位和 32 位代码间进行转换,然后将控制转移给目标函数。注意,ODBC 游标库是如何有选择地在驱动程序管理器及其驱动程序之间驻留的。此库在仅支持只能前进的游标的驱动程序上,提供了可滚动游标服务。
Oracle 和 SQL Server 处理结果集和游标方式不同。要成功地将客户应用程序从 Oracle 迁移到 SQL Server,并以最佳状态运行,了解这些差异是至关重要的。
在 Oracle 中,当在客户应用程序中被提取时,任何 SELECT 命令的结果集都被作为只能前进的游标处理。不管使用 ODBC、OCI,还是嵌入式 SQL 作为开发工具都是如此。
默认情况下,要返回一行,客户程序(例如,ODBC 中的 SQLFetch)执行的每个 Oracle FETCH 命令都产生一个通过网络到达服务器的往返。如果客户应用程序要每次通过网络提取不止一行,则必须在其程序中建立一个数组,并使用数组提取。
由于 Oracle 的多版本并发性模型,对于只读游标,在提取间隙服务器上不保持锁定。当程序使用 FOR UPDATE 子句指定一个可更新的游标时,语句打开时,SELECT 命令中请求的所有行均被锁定。在程序发出 COMMIT 或 ROLLBACK 请求前,这些行级锁定均有效。
在 SQL Server 中,SELECT 语句并不总是与服务器上的游标关联。默认情况下,SQL Server 只是把 SELECT 语句的结果集合行依次返回给客户。SELECT 一执行,数据流就开始了。结果集数据流也可以由存储过程的 SELECT 语句返回。此外,对于单个 EXECUTE 语句,单个存储过程或一批命令可能返回多个结果集。
一旦这些默认结果集可用,SQL Server 客户就负责提取它们。对于默认结果集,客户的提取不产生到服务器的往返。相反地,对默认结果集的提取可将数据从网络缓冲区读取到程序变量中。默认结果集模型创建了一种有效的机制,在通过网络的一次往返,向客户机返回多行数据。将网络往返次数最小化,通常是改善客户/服务器应用程序性能最重要的因素。
和 Oracle 游标相比,默认结果集赋予了 SQL Server 客户应用程序更多的职责。SQL Server 客户应用程序必须立即提取 EXECUTE 语句返回的所有结果集行。如果应用程序需要逐步地将行提供给程序的其它部分,它必须将行缓存在一个内部数组中。如果它未能提取所有的结果集行,则与 SQL Server 连接仍然保持繁忙。
如果发生这种情况,在所有结果集行被提取或客户取消请求之前,在连接上不能执行其它工作。而且,在提取完成之前,服务器继续保持表数据页上的共享锁定。正是基于提取完成之前,这些共享锁定始终保持这一事实,您必须尽快提取所有的行。这与 Oracle 应用程序中常见的逐步提取方式形成了鲜明的对比。
Microsoft SQL Server 提供了“服务器游标”,来满足通过网络逐步提取结果集的需要。可通过调用 SQLSetStmtOption 设定 SQL_CURSOR_TYPE 选项,在应用程序中请求服务器游标。
当 SELECT 语句作为服务器游标执行时,EXECUTE 语句只返回游标标识符。随后的提取请求把游标标识符和指定一次提取行数的参数一起传回给服务器。服务器返回请求的行数。
在提取请求的间隙,连接保持空闲,以执行其它命令,包括其它游标的 OPEN 或 FETCH 请求。在 ODBC 术语中,它是指服务器游标允许 SQL Server 驱动程序在单个连接上支持多个活动语句。
此外,在提取请求间隙,服务器游标通常不保持锁定,所以在提取间隙可随时暂停等候用户输入,而不会影响其他用户。可以使用乐观开放冲突检测或悲观滚动锁定并发性选项,来更新服务器游标。
尽管有了这些功能,对 Oracle 开发人员而言,使用服务器游标编程比默认结果集更熟悉,但是这也不是没有代价的。和默认结果集相比:
从服务器资源角度讲,服务器游标更昂贵,因为在服务器上使用了临时存储空间,来维护游标状态信息。
用服务器游标检索给定结果集的数据更昂贵,因为 EXECUTE 语句和服务器游标中的每个检索请求均需要一个不同的到服务器的往返。
在支持批处理和存储过程方面,服务器游标灵活性较差。这是因为服务器游标每次只执行一个 SELECT 语句,而默认结果集可用于批处理和存储过程,其返回多个结果集或包含 SELECT 语句以外的其它语句。
由于这些原因,最好将服务器游标的使用限定在需要其功能的应用程序部分。使用服务器游标的一个例子可以在 Ssdemo.cpp 示例 SQL Server ODBC 程序文件的 LIST_STUDENTS 函数中找到。
Oracle RDBMS 只支持前滚游标。每行均是按照查询中指定的顺序提取到应用程序中。Oracle 不支持后移到上一个提取行的请求。向后移动的唯一办法是,关闭游标再重新打开。但遗憾的是,您会被重定位到活动查询集的第一行。
因为 SQL Server 支持可滚动游标,所以可将 SQL Server 游标定位到任何行。可以向前和向后滚动。对于许多涉及用户界面的应用程序,可滚动性是一个很有用的功能。有了可滚动游标,应用程序可以一次提取一整屏的行,并且可按照用户请求,只提取附加行。
尽管 Oracle 并不直接支持可滚动游标,但是可以使用一个 ODBC 选项,将这一限制减至最小。例如,一些 Oracle ODBC 驱动程序(例如与 Microsoft Developer Studio 可视化开发系统一起发行的 Oracle ODBC 驱动程序)可在驱动程序中提供基于客户的可滚动游标。
另外,对于任何符合兼容性级别 Level One 的 ODBC 驱动程序,ODBC 游标库均支持块可滚动游标。通过使用 RDBMS 仅向前提取,以及将结果集数据缓存在内存或磁盘上,这两种客户游标选项均能支持滚动。当请求数据时,驱动程序根据需要从 RDBMS 或本地缓存中检索数据。
对于 SELECT 语句产生的结果集,基于客户的游标还支持定位 UPDATE 和 DELETE 语句。游标库使用 WHERE 子句构造 UPDATE 或 DELETE 语句,该子句为行中的每列均指定了缓存值。
如果需要可滚动游标,且要为 Oracle 和 SQL Server 实现保持相同的源代码,那么,ODBC 游标库就是一个很有用的选择。有关 ODBC 游标库的详细信息,请参见 ODBC 文档。
由于 SQL Server 提供的提取数据选项很多,有时很难决定使用哪个选项,以及何时使用。以下是一些有用的指导原则:
默认结果集始终是将整个数据集从 SQL Server 移到客户最快捷的方法。在应用程序中寻找可使用这一功能的可能性。例如,批量报告生成通常将整个结果集处理完,在处理过程中没有用户交互和更新。
如果程序需要可更新的游标,使用服务器游标。使用定位 UPDATE 或 DELETE 语句时,默认结果集绝不可以更新。此外,服务器游标比基于客户的游标更适于更新,后者必须构建对等的 UPDATE 或 DELETE 语句,来模拟定位 UPDATE 或 DELETE。
如果程序需要可滚动的、只读的游标,ODBC 游标库和服务器游标都是很好的选择。ODBC 游标库提供 SQL Server 与 Oracle 之间的兼容行为;在每次通过网络提取多少数据方面,服务器游标则具有更大的灵活性。
当使用默认结果集或构建在默认结果集之上的 ODBC 游标库游标时,要保证尽快地将结果集提取完,应避免在服务器上保持共享锁定。
使用服务器游标时,要确保使用 SQLExtendedFetch,每次提取整块的行,而不是每次一行。这和 Oracle 应用程序中的数组类型提取是一样的。服务器游标上的每个提取请求均需要在网络上从应用程序到 RDBMS 的一个往返。
购买日用杂货提供了一个类比。假定您在食品杂货店购买了 10 袋食品,把一袋食品装上车,开回家,卸下来,再返回食品杂货店取下一袋。在现实生活中,这种场景是不太可能发生的,但是,SQL Server 和程序从服务器游标单行提取数据,就是这种情形。
如果程序只要求只能向前、只读的游标,但依赖一个连接上多个打开的游标,当知道可将整个结果集立即提取到程序变量中时,则使用默认结果集。当不知道可否立刻提取所有的行时,使用服