Oracle 数据库向 MS SQL Server 7.0 的迁移(5)
本节提供 Oracle 和 SQL Server 使用 ODBC 的方式的信息,以及使用 ODBC 开发和迁移
将应用程序代码从 Oracle 转换到 SQL Server 时,请使用下面的过程:
如果应用程序用 Oracle Pro*C 或 Oracle 调用接口 (OCI) 写成,请考虑将应用程序转
了解 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 连接。与
下图给出了 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 语句返回的所有结果集行。如果应用程序需要
逐步地将行提供给程序的其它部分,它必须将行缓存在一个内部数组中。如果它未能提取所有
如果发生这种情况,在所有结果集行被提取或客户取消请求之前,在连接上不能执行其它
工作。而且,在提取完成之前,服务器继续保持表数据页上的共享锁定。正是基于提取完成之
前,这些共享锁定始终保持这一事实,您必须尽快提取所有的行。这与 Oracle 应用程序中常
Microsoft SQL Server 提供了“服务器游标”,来满足通过网络逐步提取结果集的需要
。可通过调用 SQLSetStmtOption 设定 SQL_CURSOR_TYPE 选项,在应用程序中请求服务器游
当 SELECT 语句作为服务器游标执行时,EXECUTE 语句只返回游标标识符。随后的提取请
求把游标标识符和指定一次提取行数的参数一起传回给服务器。服务器返回请求的行数。
在提取请求的间隙,连接保持空闲,以执行其它命令,包括其它游标的 OPEN 或 FETCH
请求。在 ODBC 术语中,它是指服务器游标允许 SQL Server 驱动程序在单个连接上支持多个
此外,在提取请求间隙,服务器游标通常不保持锁定,所以在提取间隙可随时暂停等候用
户输入,而不会影响其他用户。可以使用乐观开放冲突检测或悲观滚动锁定并发性选项,来更
尽管有了这些功能,对 Oracle 开发人员而言,使用服务器游标编程比默认结果集更熟悉
从服务器资源角度讲,服务器游标更昂贵,因为在服务器上使用了临时存储空间,来维护
用服务器游标检索给定结果集的数据更昂贵,因为 EXECUTE 语句和服务器游标中的每个
在支持批处理和存储过程方面,服务器游标灵活性较差。这是因为服务器游标每次只执行
一个 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 应用程序中的数组类型提取是一样的。服务器游标上的每个提取请求均需要
购买日用杂货提供了一个类比。假定您在食品杂货店购买了 10 袋食品,把一袋食品装上
车,开回家,卸下来,再返回食品杂货店取下一袋。在现实生活中,这种场景是不太可能发生
的,但是,SQL Server 和程序从服务器游标单行提取数据,就是这种情形。
如果程序只要求只能向前、只读的游标,但依赖一个连接上多个打开的游标,当知道可将
整个结果集立即提取到程序变量中时,则使用默认结果集。当不知道可否立刻提取所有的行时
这个策略不像听起来那么困难。大多数程序员知道,何时使用单独选择,该选择至多返回
一行数据。对于单独提取,使用默认结果集比使用服务器游标更有效。
有关这一技巧的例子,请参见 Ssdemo.cpp 示例 SQL Server ODBC 程序文件中的
LIST_STUDENTS 函数。如果 SELECT 语句返回不止一行时,注意服务器游标是如何被请求的。
在此执行步之后,行集大小被设为一个合理的批处理大小。这允许同一个 SQLExtendedFetch
有关实现游标的详细信息,请参见 SQL Server Books Online。
ODBC 驱动程序使用语句句柄 (hstmt),跟踪程序中的每个活动 SQL 语句。语句句柄总是
与 RDBMS 连接句柄 (hdbc) 关联。ODBC 驱动程序管理器使用连接句柄,把请求的 SQL 语句
送到指定的 RDBMS。大多数 Oracle ODBC 驱动程序允许每个连接上有多个语句句柄。但是,
当使用默认结果集时,SQL Server ODBC 驱动程序只允许每个连接上有一个活动的语句句柄。
当使用 SQL_ACTIVE_STATEMENTS 选项查询时,此 SQL Server 驱动程序的 SQLGetInfo 函数
返回值 1。当语句选项设定为,使用服务器游标时,则在每个连接句柄上支持多个活动语句。
有关设定语句选项,请求服务器游标的详细信息,请参见 SQL Server Books Online。
与任何可用的 Oracle ODBC 驱动程序相比,SQL Server ODBC 驱动程序提供的一组数据
类型映像更丰富。
timestamp 数据类型被转换为 SQL_BINARY 数据类型。这是因为 timestamp 列中的值不
是 datetime 数据,而是 binary(8) 数据。它们用于指示行上 SQL Server 活动的顺序。
下表给出了 Oracle 数据类型和用于 Oracle 的 Microsoft ODBC 驱动程序的对应关系。
其他厂商的 Oracle ODBC 驱动程序其数据类型对应可能不同。
ODBC Extended SQL 标准给 ODBC 提供了 SQL 扩展,它支持 Oracle 和 SQL Server 中
提供的非标准高级 SQL 功能。该标准允许 ODBC 驱动程序将通用的 SQL 语句转换为原本的
这个标准处理外部联接,例如谓词转义符、标量函数、日期/时间/时间戳值和存储程序。
--(*vendor(Microsoft), product(ODBC) extension *)--
OR
{extension}
转换在运行时发生,并且不需要修改任何程序代码。在大多数应用程序开发过程中,最好
的方法是编写一个程序,然后在程序运行时允许 ODBC 执行 RDBMS 转换。
Oracle 和 SQL Server 没有兼容的外部联接语法。可使用 ODBC Extended SQL 外部联
接语法,解决这一问题。Microsoft SQL Server 语法和 ODBC Extended SQL/SQL-92 语法是
一致的。唯一的差别是 {oj } 容器。
与 SQL Server 应用程序相比,日期格式对 Oracle 应用程序的影响更大。Oracle 期望
的日期格式是“DD-MON-YY”。如果不是这样,使用 TO_CHAR 或 TO_DATE 函数与日期格式模
Microsoft SQL Server 自动转换最常用的日期格式,当自动转换不能执行时,它还提供
正如表中所示,ODBC Extended SQL 可用于两种数据库中。SQL Server 不需要转换函数
。但是,ODBC 简写语法对 Oracle 和 SQL Server 是通用的。
用于调用存储程序的 ODBC 简写语法支持 Microsoft SQL Server 存储过程、Oracle 存
储过程、函数和包。可选的“?=”捕获 Oracle 函数或 SQL Server 过程的返回值。参数语法
用于向被调用的程序传递值和从被调用的程序返回值。在大多数情况中,同一语法对 Oracle
在下面的例子中,SHOW_RELUCTANT_STUDENTS 函数是 Oracle 包 P1 的一部分。包中必须
有该函数,因为它从 PL/SQL 游标中返回多个行。当调用存在于包中的函数或过程时,包的名
包 P1 中的 SHOW_RELUCTANT_STUDENTS 函数使用包游标,检索多行数据。必须调用该函
数来请求每一行。如果不再检索其它行,函数返回值 0,表示不再检索其它行。这个示例
Oracle 包及其函数的性能可能不够满意。对于这种类型的操作,SQL Server 过程更为有效
。
由于 Oracle 和 SQL Server ODBC 驱动程序的多样性,所以,并非总能得到相同的扩展
SQL 函数转换字符串。为了便于应用程序调试,可考虑使用 SQLNativeSql 函数。这个函数
对于包含标量函数 CONVERT 的下列输入 SQL 字符串,其可能结果如下。SSN 列定义为
类型 CHAR(9),并被转换成数值。
Common.cpp 示例程序没有使用 ODBC Extended SQL 语法。相反地,它使用一系列视图和
过程,将不是 Oracle 和 SQL Server 共有的语句和函数隐藏起来。这个程序尽管是使用
ODBC 编写的,但其目的在于,让应用程序编程人员知道在编写通用程序时,如何轻而易举地
在非 ODBC 开发环境中使用时,这些技巧和策略获得了最佳效果。如果正在使用 ODBC,
则考虑使用 ODBC Extended SQL 语法,克服 Oracle 和 SQL Server 之间的任何语法上的差
一旦用户修改数据时,Oracle 就会自动进入事务模式。必须紧跟着一个显式 COMMIT,
将更改写入数据库。如果用户要撤消更改,可执行 ROLLBACK 语句。
默认情况下,在更改发生时,SQL Server 自动提交更改。在 ODBC 中,这称为自动提交
模式。如果不想使用此模式,可使用 BEGIN TRANSACTION 语句,指定包含事务的语句块的起
始处。这个语句执行后,接下来是一个显式 COMMIT TRANSACTION 或 ROLLBACK TRANSACTION
要保证与 Oracle 应用程序的兼容性,建议使用 SQLConnectionOption 函数,将 SQL
Server 应用程序置为隐性事务模式。要实现这一点,SQL_AUTOCMMIT 选项必须设置为
SQL_AUTOCOMMIT_OFF。从示例程序中截取的这段代码例证了这个概念:
SQLSetConnectOption(hdbc1, SQL_AUTOCOMMIT,-sql_AUTOCOMMIT_OFF);
SQL_AUTOCOMMIT_OFF 选项指示驱动程序使用隐性事务。默认选项 SQL_AUTOCOMMIT_ON
选项指示驱动程序使用自动提交模式,其中每条语句在执行后均自动提交。从手动提交模式转
为自动提交模式,就会将连接上任何打开的事务进行提交。
如果设定了 SQL_AUTOCOMMIT_OFF 选项,应用程序必须使用 SQLTransact 函数显式地提
交或回滚事务。对于与一个连接句柄关联的所有语句句柄上的所有活动操作,此函数均请求一
个提交或回滚操作。它还可以请求,对所有与环境句柄有关的连接句柄执行一个提交或回滚操
SQLTransact(henv1, hdbc1, SQL_ROLLBACK);
(SQLTransact(henv1, hdbc1, SQL_COMMIT);
当自动提交模式关闭时,驱动程序向服务器发出 SET IMPLICIT_TRANSACTION ON 语句。
在手动提交模式中,要提交或回滚一个事务,应用程序必须调用 SQLTransact。SQL
Server 驱动程序发出 COMMIT TRANSACTION 语句提交事务;发出 ROLLBACK TRANSACTION 语
注意,手动提交模式可能会负面地影响 SQL Server 应用程序的性能。每个提交请求都需
要一个不同的到服务器的往返,以发送 COMMIT TRANSACTION 字符串。
如果有单个原子事务处理(一个 INSERT、UPDATE 或 DELETE 语句紧跟着一个 COMMIT)
在示例程序中,手动提交模式也已经打开(即便对单原子事务也是如此),例证了开发
SQL Server 应用程序,来精确模拟用于 Oracle RDBMS 的类似应用程序的操作,是多么方便
开发和管理数据库复制
本节解释 Oracle 和 Microsoft SQL Server 复制支持之间的不同点。
SQL Server 实现了快照复制,替代 Oracle 的只读快照。顾名思义,快照复制指,对数
据库中某一时刻发布的信息及时地拍一张照片或快照。快照复制比事务复制需要的持续处理器
开销要少,因为它不需要连续地监视源服务器上的数据更改。不同于复制 INSERT、UPDATE 和
DELETE 语句(事务复制的特征),或数据修改(合并复制的特征),订户由数据集的完全刷
新来更新。因此,快照复制向订户传送所有的数据,而不是只传送更改。
SQL Server 还提供事务复制,这种类型的复制在发行者的数据库事务日志中,标记已选
定的要复制事务,然后把它们作为增量变化异步地发布给订户,同时保持事务的一致性。
SQL Server 实现合并复制,替代 Oracle 的可更新快照和 Oracle 的多主控复制模型。
合并复制是一种复制类型,它允许站点对复制的数据进行自主更改,并随后将所有站点更改进
行合并。合并复制并不保证事务的一致性。
SQL Server 提供异类复制,这是将数据发行给异类订户的最简单方法,它使用 ODBC 并
创建一个从发行者到 ODBC 订户的强制订阅。但是,作为替代方法,您可以创建一个发行,然
后用嵌入式分布控制创建一个应用程序。嵌入式控制实现了从发行者到订户的强制订阅。对于
ODBC 订户,订阅数据库没有所执行复制的管理能力。
分发服务器作为 ODBC 客户,连接到所有的订阅服务器。复制要求所有分发服务器上均要
安装 32 位 ODBC 驱动程序。SQL Server 安装程序在基于 Windows NT 的计算机上自动安装
不需为 SQL Server 订阅服务器预先配置 ODBC 数据源,因为分发进程只使用订户的网络
SQL Server 也包括一个 ODBC 驱动程序,它支持 Oracle 对 SQL Server 的订阅。该驱
动程序只用于基于 Intel 的计算机。要向 Oracle ODBC 订户复制,必须从 Oracle 或软件
如果在 Windows NT 注册表中提供了密码,Oracle ODBC 就会连接到 Oracle,而不需请
求密码。如果 Windows NT 注册表中没有提供密码,则在 SQL Server Enterprise Manager
的新建 ODBC 订户对话框中指定 DSN 时,必须输入 Oracle ODBC 数据源的用户名和密码。
当向 Oracle ODBC 订户复制时,就会有以下限制:
datetime 数据类型对应为 DATE。Oracle DATE 数据类型的范围是 4712 B.C. 到 4712
A.D.。如果向 Oracle 复制,检查复制列的 SQL Server datetime 条目是否在这个范围内。
复制的表只能有一个 text 或 image 列。
datetime 数据类型对应为 Oracle CHAR 数据类型。
SQL Server float 和 real 数据类型的范围与 Oracle 不同。
其他 ODBC 订户类型的驱动程序必须符合通用 ODBC 订户的 SQL Server 复制要求。
必须符合 ODBC Level 1。
分布进程运行的处理器体系结构必须是 32 位,并且是线程安全的。
必须能够完成事务处理。
必须支持数据定义语言 (DDL)。
不能是只读的。