非Access数据库在VB的编程及应用
摘 要 Visual Basic 有 着 强 大 的 数 据 库 存 取 能 力 , 不 仅 能 够 直 接 支 持 Ms Access 数 据 库 , 而 且 通 过 其 内 部 安 装 的 ISAM 驱 动 程 序 使 它 能 间 接 支 持 FoxPro 、 dBASE 等 外 来 数 据 库 。 本 文 不 仅 从 VB 数 据 库 体 系 结 构 的 角 度 探 讨 了 VB 对 这 些 外 来 数 据 库 的 支 持 , 还 结 合 了 一 些 实 例 具 体 阐 述 了 使 用 数 据 库 存 取 对 象 变 量 的 方 法 实 现 这 些 外 来 数 据 库 的 新 建 、 库 结 构 修 改 、 显 示 及 其 运 行 环 境 设 置 。 关 键 词 Visual Basic Access 外 来 数 据 库 数 据 库 存 取 对 象 变 量 库 结 构 作 为 一 个 功 能 较 完 备 的 Windows 软 件 开 发 平 台 , Visual Basic 专 业 版 提 供 了 对 数 据 库 应 用 的 强 大 支 持 。 尤 其 提 供 了 使 用 数 据 控 件 和 绑 定 控 制 项 , 使 用 数 据 库 存 取 对 象 变 量 ( Data Access Object Variable ) , 直 接 调 用 ODBC 2.0 API 接 口 函 数 等 三 种 访 问 数 据 库 的 方 法 。 对 其 标 准 内 置 的 Ms Access 数 据 库 , 它 可 以 提 供 不 弱 于 专 业 数 据 库 软 件 的 支 持 , 可 以 进 行 完 整 的 数 据 库 维 护 、 操 作 及 其 事 务 处 理 。 在 VB 中 , 将 非 Access 数 据 库 称 为 外 来 数 据 库 。 对 于 FoxPro 、 dBASE 、 Paradox 等 外 来 数 据 库 。 虽 然 借 助 VB 的 Data Manager 能 够 对 这 些 数 据 库 进 行 NEW 、 OPEN 、 DESIGN 、 DELETE 等 操 作 , 但 在 应 用 程 序 的 运 行 状 态 中 并 不 能 从 底 层 真 正 实 现 这 些 功 能 。 本 文 从 使 用 数 据 库 存 取 对 象 变 量 的 方 法 出 发 , 实 现 了 非 Access 格 式 数 据 库 ( 以 FoxPro 数 据 库 为 例 ) 的 建 新 库 、 拷 贝 数 据 库 结 构 、 动 态 调 入 等 操 作 , 阐 述 了 从 编 程 技 巧 上 弥 补 VB 对 这 些 外 来 数 据 库 支 持 不 足 的 可 行 性 。 一 、 VB 数 据 库 的 体 系 结 构 具 体 的 VB 的 数 据 库 结 构 请 先 看 下 图 。 可 见 VB 数 据 库 的 核 心 结 构 是 所 谓 的 MicroSoft JET 数 据 库 引 擎 , JET 引 擎 的 作 用 就 像 是 一 块 “ 面 板 ” , 在 其 上 可 以 插 入 多 种 ISAM ( Indexed Sequential Access Method , 即 索 引 顺 序 存 取 方 法 ) 数 据 驱 动 程 序 。 JET 引 擎 为 Access 格 式 数 据 库 提 供 了 直 接 的 内 部 ( build-in ) 支 持 , 这 就 是 VB 对 Access 数 据 库 具 有 丰 富 支 持 的 真 正 原 因 。 VB 专 业 版 中 提 供 了 FoxPro 、 dBASE ( 或 Xbase ) 、 Paradox 、 Btrieve 等 数 据 库 的 ISAM 驱 动 程 序 , 这 就 使 得 VB 能 支 持 这 些 数 据 库 格 式 。 另 外 , 其 他 的 许 多 兼 容 ISAM 的 驱 动 程 序 也 可 以 通 过 从 厂 商 的 售 后 服 务 得 到 。 因 而 从 理 论 上 说 , VB 能 支 持 所 有 兼 容 ISAM 的 数 据 库 格 式 ( 前 提 是 只 需 获 得 这 些 数 据 库 的 ISAM 驱 动 接 口 程 序 ) 。 由 上 可 见 , Ms JET 引 擎 实 质 上 提 供 了 : 一 个 符 合 ANSI 标 准 的 语 法 分 析 器 ; 为 查 询 结 果 集 的 使 用 而 提 供 的 内 存 管 理 功 能 ; 同 所 支 持 的 数 据 库 的 外 部 接 口 ; 为 应 用 代 码 提 供 的 内 部 接 口 。 实 际 上 , 在 VB 中 从 一 种 数 据 库 类 型 转 化 为 另 一 种 数 据 库 类 型 几 乎 不 需 要 或 只 需 要 很 少 的 代 码 修 改 。 而 且 , 尽 管 dBASE 、 Paradox 本 身 的 DDL ( Data Definition Language , 即 数 据 定 义 语 言 ) 和 DML ( Data Manipulation Language , 即 数 据 操 纵 语 言 ) 是 非 结 构 化 查 询 的 , 但 它 们 仍 然 可 以 使 用 VB 的 SQL 语 句 和 JET 引 擎 来 操 纵 。 从 VB 的 程 序 代 码 的 角 度 来 看 , ODBC , ISAM 驱 动 程 序 以 及 Ms Access 数 据 库 的 整 个 外 部 结 构 够 可 以 统 一 为 一 个 一 致 的 编 程 接 口 。 也 即 是 说 , 提 供 给 VB 应 用 程 序 员 的 记 录 集 对 象 视 图 同 所 使 用 的 数 据 库 格 式 及 类 型 是 相 互 独 立 的 。 即 对 FoxPro 等 数 据 库 仍 然 可 以 使 用 众 多 的 数 据 库 存 取 对 象 变 量 , 这 就 为 非 Access 数 据 库 的 访 问 提 供 了 最 重 要 的 方 法 。 二 、 使 用 非 Access 数 据 库 时 的 参 数 设 置 及 配 置 文 件 的 参 数 读 取 如 果 在 VB 的 程 序 中 使 用 了 数 据 库 的 操 作 , 将 应 用 程 序 生 成 EXE 文 件 或 打 包 生 成 安 装 程 序 后 , 则 必 须 提 供 一 个 配 置 ( .INI ) 文 件 , 在 INI 文 件 中 可 以 对 不 同 类 型 的 数 据 库 进 行 设 置 。 如 果 找 不 到 这 个 INI 文 件 , 将 会 导 致 不 能 访 问 数 据 库 。 通 常 情 况 下 , INI 文 件 的 文 件 名 和 应 用 程 序 的 名 称 相 同 , 所 以 如 果 没 有 指 明 , VB 的 程 序 会 在 Windows 子 目 录 中 去 找 和 应 用 程 序 同 名 的 INI 文 件 。 可 以 使 用 VB 中 的 SetDataAccessOptions 语 句 来 设 置 INI 文 件 。 SetDataAccessOptions 语 句 的 用 法 如 下 : SetDataAccessOptions 1 , IniFileName 其 中 IniFileName 参 数 指 明 的 是 INI 文 件 的 带 路 径 的 文 件 名 。 值 得 注 意 的 是 , 当 应 用 程 序 找 不 到 这 个 INI 文 件 时 , 或 在 调 用 OpenDataBase 函 数 时 对 其 Connect 参 数 值 没 有 设 定 为 VB 规 定 的 标 准 值 , 如 对 FoxPro 2.5 格 式 设 定 为 了 “ FoxPro; ” ( 应 为 “ FoxPro 2.5; ” ) , 或 者 没 有 安 装 相 应 的 ISAM 驱 动 程 序 , 则 此 时 VB 会 显 示 一 条 错 误 信 息 “ Not Found Installable ISAM ” 。 通 常 , INI 文 件 在 应 用 程 序 分 发 出 去 以 前 已 经 生 成 , 或 者 在 安 装 时 动 态 生 成 , 也 可 以 在 应 用 程 序 中 自 己 生 成 。 通 常 这 种 INI 文 件 中 有 “ [Options] ” 、 “ [ISAM] ” 、 “ [Installed ISAMs] ” 、 “ [FoxPro ISAM] ” 、 “ [dBASE ISAM] ” 、 “ [Paradox ISAM] ” 等 设 置 段 , 对 于 一 个 完 整 的 应 用 程 序 则 还 应 有 一 个 属 于 应 用 程 序 自 己 的 设 置 段 如 “ [MyDB] ” 。 可 在 其 中 设 置 DataType 、 Server 、 DataBase 、 OpenOnStartup 、 DisplaySQL 、 QueryTimeOut 等 较 为 重 要 的 数 据 库 参 数 , 并 以 此 限 定 应 用 程 序 一 般 的 运 行 环 境 。 Windows API 接 口 函 数 在 Kernel.exe 动 态 链 接 库 中 提 供 了 一 个 OSWritePrivateProfileString 函 数 , 此 函 数 能 按 Windows 下 配 置 文 件 ( .INI ) 的 书 写 格 式 写 入 信 息 。 在 通 常 情 况 下 , 应 用 程 序 还 需 要 在 运 行 时 读 取 配 置 文 件 内 相 关 项 的 参 数 。 比 如 PageTimeOut ( 页 加 锁 超 时 时 限 ) 、 MaxBufferSize ( 缓 冲 区 大 小 ) 、 LockRetry ( 加 锁 失 败 时 重 试 次 数 ) 等 参 数 , 通 过 对 这 些 参 数 的 读 取 对 应 用 程 序 运 行 环 境 的 设 定 、 潜 在 错 误 的 捕 获 等 均 会 有 很 大 的 改 善 。 设 此 应 用 程 序 的 配 置 文 件 为 MyDB.INI , 则 具 体 过 程 如 下 : Funtion GetINIString$( Byval Fname$ , Byval szItem$ , Byval szDeFault$ ) ’ 此 自 定 义 子 函 数 实 现 INI 文 件 内 设 置 段 内 参 数 的 读 取 Dim Tmp As String , x As Integer Tmp = String( 2048,32 ) x = OSGetPrivateProfileString( Fname$ , szItem$ , szDefault$ , Tmp , Len(Tmp) , “ MyDB.INI ” ) GetINIString = Mid$( Tmp,1,x ) End Function 以 下 这 些 函 数 的 声 明 可 写 在 模 块 文 件 内 , 且 每 个 函 数 的 声 明 必 须 在 一 行 内 Declare Function OSGetPrivateProfileString% Lib "Kernel" Alias "GetPrivateProfileString" (ByVal AppName$, ByVal KeyName$, ByVal keydefault$, ByVal ReturnString$, ByVal NumBytes As Integer, ByVal FileName$) Declare Function OSWritePrivateProfileString% Lib "Kernel" Alias "WritePrivateProfileString" (ByVal AppName$, ByVal KeyName$, ByVal keydefault$, ByVal FileName$) Declare Function OSGetWindowsDirectory% Lib "Kernel" Alias "GetWindowsDirectory" (ByVal a$, ByVal b%) Sub Form1_Load( ) Dim st As String Dim x As Integer Dim tmp As String tmp = String$( 255, 32 ) ’ 在 INI 文 件 内 为 各 种 数 据 库 格 式 指 明 已 安 装 的 相 应 ISAM 驱 动 程 序 x = OSWritePrivateProfileString(" Installable ISAMS", "Paradox 3.X", "PDX110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "Installable ISAMS", "dBASE III", "XBS110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "Installable ISAMS", "dBASE IV", "XBS110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "Installable ISAMS", "FoxPro 2.0", "XBS110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "Installable ISAMS", "FoxPro 2.5", "XBS110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "Installable ISAMS", "Btrieve", "BTRV110.DLL", "MyDB.INI" ) x = OSWritePrivateProfileString( "dBase ISAM", "Deleted", "On", "MyDB.INI" ) ’ 指 明 INI 文 件 的 位 置 x = OSGetWindowsDirectory( tmp, 255 ) st = Mid$( tmp, 1, x ) SetDataAccessOption 1, st + "\mydb.ini" ’ 获 得 INI 文 件 一 些 参 数 gwMaxGridRows = Val(GetINIString( “ MyDB.INI ” ,"MaxRows", "250" )) glQueryTimeout = Val(GetINIString( “ MyDB.INI ” ,"QueryTimeout", "5" )) glLoginTimeout = Val(GetINIString( “ MyDB.INI ” ,"LoginTimeout", "20" )) End Sub 三 、 数 据 存 取 对 象 变 量 对 外 来 数 据 库 编 程 的 方 法 及 其 实 例 在 VB 专 业 版 数 据 库 编 程 的 三 种 方 法 中 , 第 二 种 — 使 用 数 据 库 存 取 对 象 变 量 ( DAO ) 的 方 法 最 具 有 功 能 强 大 、 灵 活 的 特 点 。 它 能 够 在 程 序 中 存 取 ODBC 2.0 的 管 理 函 数 ; 可 以 控 制 多 种 记 录 集 类 型 : Dynaset , Snapshot 及 Table 记 录 集 合 对 象 ; 可 以 存 储 过 程 和 查 询 动 作 ; 可 以 存 取 数 据 库 集 合 对 象 , 例 如 TableDefs , Fields , Indexes 及 QueryDefs ; 具 有 真 正 的 事 物 处 理 能 力 。 因 而 , 这 种 方 法 对 数 据 库 处 理 的 大 多 数 情 况 都 非 常 适 用 。 由 于 VB 中 的 记 录 集 对 象 与 所 使 用 的 数 据 库 格 式 及 类 型 是 相 互 独 立 的 , 所 以 在 非 Access 数 据 库 中 也 可 以 使 用 数 据 库 存 取 对 象 变 量 的 方 法 。 因 而 对 FoxPro 等 外 来 数 据 库 而 言 , 使 用 数 据 库 存 取 对 象 变 量 的 方 法 同 样 也 是 一 种 最 佳 的 选 择 。 有 一 点 需 要 注 意 的 是 , VB 的 标 准 版 中 仅 能 使 用 数 据 控 件 ( Data Control ) 对 数 据 库 中 的 记 录 进 行 访 问 , 主 要 的 数 据 库 存 取 对 象 中 也 仅 有 Database 、 Dynaset 对 象 可 通 过 数 据 控 件 的 属 性 提 供 , 其 它 的 重 要 对 象 如 TableDef 、 Field 、 Index 、 QueryDef 、 Snapshot 、 Table 等 均 不 能 在 VB 的 标 准 版 中 生 成 , 所 以 使 用 数 据 存 取 对 象 变 量 的 方 法 只 能 用 VB 3.0 以 上 的 专 业 版 。 ( 一 ) 、 非 Access 数 据 库 的 新 建 及 库 结 构 的 修 改 VB 专 业 版 中 的 数 据 库 存 取 对 象 变 量 可 以 分 为 两 类 , 一 类 用 于 数 据 库 结 构 的 维 护 和 管 理 , 另 一 类 用 于 数 据 的 存 取 。 其 中 表 示 数 据 库 结 构 时 可 以 使 用 下 面 的 对 象 : DataBase 、 TableDef 、 Field 、 Index , 以 及 三 个 集 合 ( Collection ) : TableDefs 、 Fields 和 Indexes 。 每 一 个 集 合 都 是 由 若 干 个 对 象 组 成 的 , 这 些 数 据 对 象 的 集 合 可 以 完 全 看 作 是 一 个 数 组 , 并 按 数 组 的 方 法 来 调 用 。 一 旦 数 据 库 对 象 建 立 后 , 就 可 以 用 它 对 数 据 库 的 结 构 进 行 修 改 和 数 据 处 理 。 对 于 非 Access 数 据 库 , 大 部 分 都 是 对 应 于 一 个 目 录 , 所 以 可 以 使 用 VB 的 MkDir 语 句 先 生 成 一 个 目 录 , 亦 即 新 建 一 个 数 据 库 。 而 每 一 个 非 Access 数 据 库 文 件 可 看 作 是 此 目 录 下 的 一 个 数 据 表 ( Table ) , 但 实 际 上 它 们 是 互 相 独 立 的 。 下 面 是 新 建 一 个 FoxPro 2.5 格 式 数 据 库 的 程 序 实 例 。 Sub CreateNew ( ) Dim Db1 As database , Td As TableDefs Dim T1 As New Tabledef , F1 As New Field , F2 As New Field , F3 As New Field Dim Ix1 As New Index Dim Path As String Const DB_TEXT = 10 , DB_INTEGER = 3 ChDir "\" Path$ = InputBox( " 请 输 入 新 路 径 名 : ", " 输 入 对 话 框 " ) MkDir Path$ ’ 新 建 一 个 子 目 录 Set Db1 = OpenDatabase(Path$, True, False, "FoxPro 2.5;") Set Td = Db1.TableDefs T1.Name = "MyDB" ’ 新 建 一 个 数 据 表 , 数 据 表 名 为 MyDB F1.Name = "Name" , F1.Type = DB_TEXT , F1.Size = 20 F2.Name = "Class" , F2.Type = DB_TEXT , F2.Size = 20 F3.Name = "Grade" , F3.Type = DB_INTEGER T1.Fields.Append F1 ’ 向 数 据 表 中 添 加 这 些 字 段 T1.Fields.Append F2