|
简介 在本文中,我将演示如何使用 IBM DB2® Universal Database™ 作为用 Borland C++Builder® 6 Enterprise 和 dbExpress™ 编写的应用程序的后台数据库。我将重点展示 C++Builder dbExpress 组件如何连接到 DB2 以及如何使用它们在数据库表之上构建可视化的、数据驱动的窗体。
使用 DB2 Personal Edition v8.1 如果您不能连接到 DB2 数据库,那么可以向 IBM 申请一张 CD 或者从 IBM Web 站点中的 http://www14.software.ibm.com/webapp/download/category.jsp?s=c&cat=data 下载一个免费的试用版,或者 DB2 最近的 beta 版。(对于本文,我使用的是从这个 URL 下载的用于 Windows® NT® 或 2000 的 IBM DB2 Universal Database, Version 8.1 的具有 90 天有效期的试用版本。)
安装好之后,DB2 为我创建了 SAMPLE 数据库,本文中我将使用这个数据库。如果您想和我一起进行操作的话,您需要使用 DB2 的 “First Steps” 实用工具创建那个数据库,对于那些没有很多 DB2 使用经验的人我强烈推荐这个工具。
使用 C++Builder 6 和 dbExpress C++Builder 包含很多数据访问库,例如 Borland Database Engine (BDE)、dbGo for ADO 和 SQL Links。较后的版本具有连接到 DB2 数据库的能力,但是不再提供对 SQL Links 的支持。幸运的是,C++Builder 提供了一种叫做 dbExpress 的替代的数据访问技术,这是一个用于 C++Builder、 Borland Delphi™ 和 Borland Kylix™ (Linux下) 的、强大的、跨平台的数据访问层。这些工具的企业版包含一个用于 DB2 的 dbExpress 驱动程序,这在本文中将会用到。
连接到 DB2 数据库
一开始要确保 DB2 在运行,然后使用 File -> New CLX Application 新建一个 CLX 项目;CLX 是用于跨平台开发的 Borland 组件库。通过使用 CLX 技术,之后您就可以在 Linux® (Intel 平台)上使用 Kylix — Linux 下基于 ANSI/ISO C++ 和 Delphi 编程语言的一个 RAD IDE 重新编译应用程序。
将空的主窗体保存为 MainForm.cpp,项目文件保存为 DB2BCB6.bpr。现在就要连接 DB2 数据库了,首先您需要从 C++Builder 组件面板中的 dbExpress 页拖放一个 TSQLConnection 组件。TSQLConnection 组件负责使用 dbExpress 层通过 DB2 客户机连接到 DB2 DBMS。
您可以使用 DriverName 属性选择一个驱动程序,例如 DB2、InterBase、MYSQL 或者 Oracle。然而,您通常已经在 ConnecionName 中定义了特定的(到特定数据库的)连接信息,所以您也可以使用那个属性,并选择 DB2Connection 值。一旦设置好了 DriverName 或者 ConnectionName 属性值,其它的属性就会同时自动地得到一个值,例如 GetDriverFunc、LibraryName 和 VendorLib 属性。
将 LibraryName 设置为 dbexpdb2.dll,并指定用来与 DB2 交谈的 dbExpress 库(C++Builder 自带),GetDriverFunc 是在那个库中的入口点的名字。将 VendorLib 设置为 db2cli.dll,并指定 DB2 需要的 DB2 库的实际的名字(如果您安装了 DB2 客户机,这个名字就由 IBM 提供,并且如果您的客户端机器要首先连接和使用 DB2,那么这个名字就应该在您的客户端机器上)。
如果您右键点击 TSQLConnection 组件,您就可以在 dbExpress Connections Properties 对话框中指定更详细的连接选项(见图 1)。注意我已经将 Database 设置为 SAMPLE,还要注意您可以在这里事先指定好您的 User_Name 和 Password。

图 1. dbExpress 连接属性
如果所有设置都正确的话,您就可以关闭 Connections Properties 对话框,然后将 TSQLConnection 组件的 Connected 属性设置为 True。这样就会导致弹出一个 Database Login 对话框(见图 2)。如果不想要这个对话框(因为您已经事先在 Connection Properties 那里指定了 User_Name 和 Password),您可以将 TSQLConnection 组件的 LoginPrompt 属性设置为 false。

图 2. Database Login 对话框
在成功登录之后,您就可以连接到 DB2 SAMPLE 数据库了并使用 TSQLTable、TSQLQuery、TSQLStoredProc 或者 TSQLDataSet 组件从数据库中来检索信息了。
从数据库中检索信息
要首先使用 TSQLTable,请拖放这个组件到窗体中,然后将其 Connection 属性设为 TSQLConnection 组件。现在您可以使用 TableName 属性从 SAMPLE 数据库的11个表(分别是 CL_SCHED、DEPARTMENT、EMP_ACT、EMP_PHOTO、EMP_RESUME、EMPLOYEE、IN_TRAY、ORG、PROJECT、SALES 和 STAFF)中选择一个。这里我们选择 employee 表。
在继续之前,要注意 dbExpress 与 C++Builder 中的一些老数据访问库(例如 BDE 和 SQL Links)有所不同:dbExpress 数据集是只读的和单向的数据集。这就意味着您只能打开表然后从第一条记录遍历到最后一条记录,而不能反向移动或者跳到最后一条记录,而且您还不能对表做任何更改。
实际上这就像执行一个 SQL 查询,每次只能查看一下结果记录,而其它什么都不能做。dbExpress 数据集采用这种方式的主要原因是速度。这样做的结果是数据访问速度快并且开销少。除此之外,您还可能面临一些只需要对结果集遍历一次的情况(例如在报表或者 Web 服务器应用程序中),所以如果您并不总是需要,为什么还要增加开销呢?
在激活了 TSQLTable 之后,便可以取得 employee 表的内容(作为一个只读的和单向的数据集)。要查看数据并对其作出更改,必须将该内容放到一个本地缓存 —— TClientDataSet。做法如下,从组件面板的 Data Access 页拖放一个 TClientDataSet 和一个 TDataSetProvider 组件。您必须将 TDataSetProvider 使用 DataSet 属性连接到 TSQLTable 组件,这样 TDataSetProvider 就可以为 TClientDataSet 提供记录。最后一步,您必须将 TClientDataSet 的 ProviderName 属性指向 TDataSetProvider。
现在当您打开 TClientDataSet 的时候,它会发送一个对数据的请求给 TDataSetProvider,TDataSetProvider 就会打开 TSQLTable 组件并从 DB2 employee 表中检索记录(通过到 DB2 数据库的 TSQLConnection)。
要显示 employee 表的内容,您还需要两到三个组件,第一个是 TDataSource 组件(也在 Data Access 页)。这个组件充当 TClientDataSet 和 C++Builder 中任何所谓的数据感知组件(都在组件面板的 Data Controls 页)之间的通路。将 TDataSource 的 DataSet 属性指向 TClientDataSet。现在拖放一个 TDBGrid 组件和一个 TDBNavigator 组件到窗体上,并将它们的 DataSource 属性指向 TDataSource 组件。
当您最后将 TClientDataSet 的 Active 属性设置为 true 的时候,您就可以在设计时取得即时的 DB2 数据(见图 3)。

图 3. C++Builder 在设计时与 DB2 交谈
将更新应用到数据库
现在您可以编译和运行应用程序,使其在运行时显示数据(如果您没有把 TSQLConnection 组件的 LoginPrompt 属性设置为 false 的话,在开始的时候会弹出一个登录对话框)。在应用程序运行期间,您可能需要对表格中的数据做些更改,当您在表格中从一条数据移动到另外一条数据的时候对数据所做的更改会自动提交给底层的数据集(在这里是 TClientDataSet)。
然而,当您关闭应用程序并再次启动它的时候,您会发现更改没有应用到 DB2 数据库中:它们只在本地内存中的 TClientDataSet 中被改变,并且现在已经丢失。要显式地把更新应用到 DB2 数据库表,您必须调用 TClientDataSet 的 ApplyUpdates 方法。您可以使用户关闭应用程序的时候自动地完成提交,在窗体的 OnClose 事件处理程序中:
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if (ClientDataSet1->ChangeCount) ClientDataSet1->ApplyUpdates(0); }
注意 ChangeCount 属性返回当前对内存中 TClientDataSet 作出的更改的数目,这些更改将应用到 DB2 数据库。
为用户提供撤销的能力
在应用更新之前,所有的更改都是保持在内存中的,所以提供给客户一个 Undo 按钮通常是一个好主意。TClientDataSet 使用 UndoLastChange 方法来支持这个功能,该方法的惟一参数指定是否要跟随更改(也就是说,您是否要将游标定位到刚刚撤销的那条记录上)。
要实现这一点,从 Standard 页拖放一个 TButton 组件到窗体上,命名为 btnUndo,将其 Caption 设置为“Undo Last Change”,然后将下面的代码添加到它的 onClick 事件处理程序中:
void __fastcall TForm1::btnUndoClick(TObject *Sender) { ClientDataSet1->UndoLastChange(true); }
这里我留给读者一个练习,添加代码使得只有在 TClientDataSet 的 ChangeCount 属性大于 0 的时候才启用这个按钮 —— 这样一来只有存在可以撤销的本地更改时才能使用该按钮。
执行存储过程和 SQL 查询
除了使用 TSQLTable 组件之外,您还可以使用 TSQLStoredProc 或者 TSQLQuery 组件。第一个组件可以用来执行存储过程,第二个组件可以用于执行 SQL 查询。不幸的是,DB2 SAMPLE 数据库不包含任何存储过程,所以您不得不相信我的话。
而对于 TSQLQuery 组件,您依然需要将它的 Connection 属性指向 TSQLConnection 组件,然后在 SQL 属性中编写一条查询语句。不幸的是,如果您需要编辑这个属性,您能用的只是一个字符串列表编辑器,它没有为构建查询(例如显示可用的表和字段名)提供任何支持。这是我从来不使用这个组件而使用 TSQLDataSet 来代替它的原因之一。
使用 TSQLDataSet 取得组合的灵活性
TSQLTable、TSQLStoredProc 和 TSQLQuery 各有其特定的用途,而 TSQLDataSet 就像一个变色龙:它可以执行这些任务中的任一个,并且可以在运行时切换任务。可以通过两个属性定义其行为:CommandType 和 CommandText。您可以将 CommandType 属性设置为 ctQuery、ctTable 或者 ctStoredProc,然后基于这个选择 CommandText 属性将显示一个 SQL Query builder,下拉列表中提供表名或者存储过程名。SQL Query builder 是一个新东西;它不是 TSQLQuery 组件本身的一部分。

图 4. SQL CommandText 编辑器
因为更多的灵活性和设计时的 SQL CommandText Editor(见图 4),所以我使用 TSQLDataSet,而从不使用 TSQLTable、TSQLQuery 或者 TSQLStoredProc 组件。但是那只是我的个人偏好。
测试一个快速数据库连接
组件面板的 dbExpress 页还包含另外一个数据集组件:TSQLClientDataSet 组件。在您不想用 TSQLDataSet-TDataSetProvider-TClientDataSet 三组合但是又要构造并测试一个快速的到 dbExpress 的连接时,可以使用 TSQLClientDataSet。TSQLClientDataSet 将这三个组件包含到一个组件中。
要看它的用法,拖放一个 TSQLClientDataSet 组件到窗体上,然后将其 Connection 属性设置为 SQLConnection1。现在您可以使用内嵌的 DataSet 属性指定一个要使用的表、查询或者存储过程名。在 Object Inspector 中双击 DataSet 属性打开它并显示其属性,例如在前面 TSQLDataSet 组件中看到的 CommandType 和 CommandText 属性。
将 CommandType 设置为 ctTable,在 CommandText 中再次选择 employee 表。现在您可以直接将 TDataSource 组件连接到这个 TSQLClientDataSet,因为 TDataSetProvider 和 TClientDataSet 已经内嵌到了 TSQLClientDataSet 之中。这样做的确方便,但是只推荐作为简单用法。对于严谨的和实际的应用,您应该使用 TSQLDataSet-TDataSetProvider 和 TClientDataSet 的组合。
监视数据库连接
有时候您需要跟踪客户机应用程序和您的 DB2 数据库之间正在发生什么。出于这个目的,TSQLConnection 组件提供了将 dbExpress 跟踪消息发送给 TSQLMonitor 组件的能力。拖放一个 TSQLMonitor 组件,将其 Connection 属性指向要跟踪的 TSQLConnection 组件。指定 Filename 应该包含日志文件(像 c:\\db2.log),将 AutoSave 属性设置为 true 以确保在应用程序关闭(或者 TSQLMonior 停用)时在这个文件中会生成日志文件。如果需要更多的灵活性以及过滤某些跟踪类别的能力,您可以使用 OnTrace 和 OnLogTrace 事件处理程序。
部署应用程序
如果编译您的项目,您可以看到一个小的可执行文件。然而,这个可执行文件使用 C++Builder 动态 RTL 和运行时包,这就意味着您还必须已经部署了这个 RTL DLL 以及包。我个人喜欢更独立的解决方案,虽然这样会产生一个比较大的可执行文件,但在部署时困扰也更少。
在部署之前,您应该进入 Project Options 的 Compiler 页(见图 5),然后点击 Release 按钮。这样会为发布目标设置所有的编译器选项。

图 5. Project Options - Compiler 页
下一步,进入同一个对话框的 Linker 页(见图 6),然后取消选定“Use dynamic RTL”选项。

图 6. Project Options - Linker 页
最后,进入 Packages 页(见图 7)然后取消选定“Build with runtime packages”选项。

图 7. Project Options - Packages 页
在作了这些更改之后,如果您再次构建 DB2BDB6 应用程序,产生的可执行文件大概有 1M 大,但是至少您不用再部署动态 RTL 或者运行时包。
然而您并没有完全解决部署的问题,因为您要保证客户端机器上安装了 DB2 客户机,并且您还需要部署 dbExpress 驱动文件 dbexpdb2.dll (位于 CBuilder\\bin 目录下)和 MIDAS.dll (它包含 DataSetProvider 和 ClientDataSet 组件的功能)。
结束语
我希望我已经向您展示了如何使用 C++Builder dbExpress 组件连接到 DB2 SAMPLE 数据库并使用其中的表。您可以使用参考资料中的 Delphi 和 DB2 来检验我写的关于使用 DB2 的文章;将代码从 Delphi 翻译到 C++ 并不困难。从现在开始,我将在我的文章中同时给出关于在 Borland RAD 工具下使用 IBM DB2 的 Delphi 和 C++ 源代码.
关于作者
Bob Swart (也称为 Dr.Bob - www.drbob42.com) 在他自己的公司 Bob Swart Training & Consultancy(eBob42)(位于荷兰 Helmond)的身份是作家、教员、顾问和 Web 管理员。Bob 编写了自己的 Delphi 培训教材,并且从 1993 年以来一直在 Delphi 和 Borland 开发者大会上发表演讲。Bob 已经撰写了数百篇文章,并且还是 Revolutionary Guide to Delphi 2、Delphi 4 Unleashed、C++Builder 4 Unleashed、C++Builder 5 Developer's Guide、Kylix Developer's Guide、Delphi 6 Developer's Guide 和即将出版的 C++Builder 6 Developer's Guide 的合著者。
[C语言系列]使用C#实现ADSL自动拨号 [Web开发]狂人采集器规则使用详解 [电脑技术]windows7快捷键使用大全 [办公软件]PowerPoint模板使用经验之谈 [办公软件]如何在PowerPoint中使用(插入)Media Player控件播… [办公软件]如何在PowerPoint中使用(插入、创建)书签及书签的… [办公软件]如何在PowerPoint中插入(使用)条形码 [办公软件]如何在PowerPoint中制作模板并使用模板 [办公软件]使用PowerPoint制作电子相册教程 [办公软件]可以使用PowerPoint来测试液晶显示器质量
|