精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● Delphi>>Kylix>>[转载]利用Kylix开发数据库应用程序

主题:[转载]利用Kylix开发数据库应用程序
发信人: yhyzh()
整理人: delfan(2001-04-01 16:09:24), 站内信件
内容
一 dbExpress:新的想象力
二 DataCLX
三 MyBase:本地XML数据库
四 建立数据库应用程序

一 dbExpress:新的想象力
    以往的对各种不同的数据库创建统一的API的努力都或多或少存在一些缺陷。有些太大、太慢和难以配置,因为它们想要做的太多;另一些则过于普通,开发者不能处理某些数据库的独特之处;还有一些受制于所写的驱动程序要么功能太弱、太慢,要么是有太多错误。Kylix通过把dbExpress---一个能读取众多数据库的统一的API---和宝兰公司的供给/解决(以下称为P/R,原文为provide/resolve)架构结合在一起,解决了上述的种种不足,能够很好地管理、编辑和更新数据。
    本论文研究了dbExpress架构和P/R机制。后面的章节介绍了Kylix进行数据库开发所用的各种构件,并通过建立一个数据库应用程序的实例来展示Kylix的强大的功能和生产力。

dbExpress架构
  dbExpress是为了以下目的而设计:
   1 最小的长度和系统资源利用
   2 最快的速度
   3 平台独立性
   4 配置简易
   5 容易开发驱动程序
    dbExpress驱动程序小而快,因为它们只提供很有限的功能。一个dbExpress驱动程序只实现以上五个接口来读取元数据、执行SQL语句和存储过程,并且返回的结果只是一个单向的只读光标。然而,通过使用DataSetProvider和ClientDataSet等构件实现宝兰公司的P/R数据读取战略,dbExpress为你提供了一个操纵SQL数据库的功能齐全、高效的、高协同性能的解决方案。

P/R架构是如何工作的
    P/R架构使用四个构件来进行数据读取和编辑。第一个是SQLConnection构件,提供与你所使用数据库的dbExpress驱动程序的连接;第二个是dbExpress数据集构件,它通过执行SQL Select命令或是存储过程以提供数据;第三个构件是DataSetProvider而第四个构件是ClientDataSet。当你打开ClientDataSet时,它要求有DataSetProvider提供的数据。DataSetProvider打开查询或存储过程构件,得到记录,然后关闭查询和存储过程构件,并提供元记录给ClientDataSet。ClientDataSet在内存中查看或修改这些记录。当记录通过代码或用户界面被增添、删除或更新时,ClientDataSet在内存中记录所有这些变化。
    为了更新数据库,你必须调用ClientDataSet构件的ApplyUpdates方法。ApplyUpdates方法先将更改记录的日志文件递交给DataSetProvider,由它启动,然后创建和执行相应的SQL命令以实现数据库的更新。当所有的更新都成功后,DataSetProvider才完成这次递交请求,否则它会退回这次递交。数据库的更新有时候会失败,比如一个更改与数据库的触发器所规定的原则发生冲突,或是在你读取数据时另一个用户已经修改了该记录,这时递交会被退回,ClientDataSet的OnReconcileError方法被激活,由你去控制处理错误。

P/R架构的好处
  1 数据更改的递交的生命期短
    长的递交生命期必然会强制数据库服务器进行数据加锁,这将降低数据的协同性能,消耗服务器资源。通过P/R架构,在数据读取和更新时,递交分别只存在短时间,这将大大减少资源的消耗,对于一个很忙的数据库服务器将大大提高性能。

  2 使任意行都可读
    在数据库应用程序中,由多表结合、存储过程和视图返回的行是不能直接编辑的。DataSetProvider提供三种工具以解决这个问题。一是如果记录包含有从单表中得到的字段,例如由存储过程返回的记录,那么唯一的问题就是如何确定表的名字。解决的办法是为DataSetProvider创建一个OnGetTableName方法以获得数据表的名字。
    第二个可能是有一个多表联合,但只更新其中一个表。那么,设置字段的ProviderFlags属性以声明该字段是将更新的。然后创建一个OnGetTableName方法以获取表名,DataSetProvider会自动创建相应的SQL命令的。
    如果你对记录的每一个表都要更新,你给DataSetProvider增加一个BeforeUpdateRecord方法,该方法能够为每个表建立SQL命令并执行。

  3 快速排序和查找
    既然ClientDataSet将记录放在内存中,它们能很快地排序。如果内存中的排序还是慢,你可以为ClientDataSet的数据在程序设计和运行时建立索引。这些内存中的索引可以让你不使用数据库的索引而快速地改变记录的显示顺序或是查找记录。

  4 自动摘要信息
    ClientDataSet能够自动处理你自己定义的诸如Sum(Price)、Sum(Cost)的复杂的摘要计算。你可以将这些摘要以任意字段或字段的组合进行分组,以得到每组的汇总。你也可以使用Min、Max、Count、Avg等计算汇总。   
 
  5 浏览数据的子集
    通过使用SQL Where语法的过滤表达式可以使你显示ClientDataSet的数据子集而不用在数据库服务器上执行另一个查询。

  6 数据的多并发视图
    克隆ClientDataSet光标使你可以同时查看数据集的多个不同视图,也可以查看相同数据的不同排序。

  7 可计算的字段
    你可以在程序设计阶段将可计算字段加入到ClientDataSet,使可计算字段成为内存中数据集的一部分。由于相关计算是通过已编译的对象化的Pascal代码实现的,所以速度很快,比SQL命令中声明的的可计算字段或是触发器中的计算复杂得多,而且不会给数据库服务器增加存储和计算的负担。
 
并不存在的限制
    将记录保存在内存中看起来会限制记录的数目。然而,传统的C/S模式的数据库应用程序为了减少网络传输量和服务器的负载也是选择很少的记录数。即使你需要处理一个比较大的记录的集合,比如说10000条记录,每条记录占100个字节,也只占用一兆内存。就算是你要处理一个很大的记录集合,ClientDataSet和DataSetProvider构件都包括了有关的属性和方法,可以使你从内存中读取、编辑和删除记录,然后处理下一组数据。

配置简易
    一个使用dbExpress开发的数据库应用程序只要求有两个共享库。一个是dbExpress驱动程序,比如说LIBSQLIB.SO,是InterBase的驱动程序;另一个是LIBMIDAS.SO,是ClientDataSet构件支持库。这减小了应用程序的大小并简化了安装。

容易创建驱动程序
    dbExpress驱动程序只要求实现在线帮助中所描述的五个接口就可以了。作为示例,宝兰公司提供了MySQL和InterBase数据库驱动程序的源代码。各数据库提供商可以轻松地创建高效稳定的驱动程序。如果你在使用某个少见或是古老的数据库系统而没有相应的驱动程序,你甚至可以自己创建一个。
二 DataCLX
    跨平台的构件库CLX包含有两组处理数据的构件。dbExpress构件提供了基本的连接和数据获得功能。而数据访问构件则通过P/R架构提供了编辑数据的能力。

dbExpress构件 
    dbExpress构件包括了一个SQLConnection构件、几个数据集构件和一个SQLMonitor构件。象所有的CLX构件一样,数据访问构件让你从构件面板上把所需要的构件拖拉到你的应用程序上就可以快速地开发了。

SQLConnection 
    SQLConnection构件可以为多个数据集构件提供数据库连接,你可以同时使用多个SQLConnection构件来连接多个数据库。定义一个数据库的连接有三种方法:使用一个已经存在的已命名的连接;创建一个新的连接;将连接参数放置在构件的Params属性。为了使用已经存在的命名连接,你只须设置ConnectionName属性即可。
    为了创建一个新的连接,双击SQLConnection构件以打开dbExpress连接编辑器,左边的连接列表框显示了所有的已定义的连接。驱动程序下拉列表能过滤所有的连接名字而只显示你选择的驱动程序的连接。右边的连接字符串表格显示所选择的连接的设置。所有你创建的连接都存在于文件dbxconnections.conf当中。下面的图显示了MySql和InterBase数据库连接文件的各个细节内容。 
(图略) 
    在创建好连接之后,你可以把它的名字赋给SQLConnection构件的ConnectionName属性。如果你使用已命名的连接,你必须将连接文件和你的应用程序一起发布,或者在目标计算机上定位该连接文件并添加。
    另一种替代的方法是先设置SQLConnection构件的DriverName属性。在弹出的下拉列表中显示了所有你安装的驱动程序。驱动程序信息都包括在文件dbxdriver.conf中。设置DriverName属性的同时也将设置LibraryName和VendorLib属性,前者包括了驱动程序共享文件的名字,后者包括了数据库供应商的客户端库文件名。 
(图略) 
    如图所示,在SQLConnection构件参数属性的编辑器中输入各连接参数。这种方法将使你的数据库连接信息都包括在你的应用程序当中了。如果你的用户要修改这些连接参数,你可以把它们存储在自己的配置文件中,并提供一个编辑该文件的方法,或者你干脆单独提供一个配置程序。
    SQLConnection构件为了更清楚地控制数据更新的递交请求,提供了StartTransaction、Commit、Rollback方法。如果你只是执行SQL命令而不要求返回数据结果,你可以使用它的Execute或ExecuteDirect方法,这时并不需要使用数据集构件。如果你需要获取数据库的某些元数据,你可以使用该构件的GetTableNames、GetFieldNames、GetIndexNames方法。 
     
数据集构件
    dbExpress提供了四个数据集构件,分别是SQLDataSet、SQLQuery、SQLStoredProc和SQLTable。SQLDataSet构件是你写任何程序都该选的构件,通过设置它的CommandType属性你可以执行SQL命令、调用存储过程或者读取一张表中所有的行和列。提供其他的数据集构件主要是为了转化使用了BDE的Window应用程序到Linux的dbExpress方便。 
    为了使用SQLDataSet构件,设置它的SQLConnection属性为你希望使用的连接构件。然后设置CommandType属性为ctQuery、ctStoredProc或ctTable。CommandText属性的值取决于CommandType属性的值。如果CommandType值为ctQuery,CommandText则包含你想执行的的SQL命令;如果是ctStoredProc,则CommandText是你选择的存储过程的名字;如果是ctTable,CommandText是你选择的表名。你可以使用Params属性来为参数化的查询和存储过程设置参数,使用DataSource属性来将SQLDataSet构件以主从关系连接到另一个数据集构件上去。 
SQLDataSet构件只提供了单向只读的数据光标。如果这正是你的需要,比如说打印一个报告,你可以只使用数据集构件,或者根据你的需求再使用一个DataSource构件。如果你需要读取、提交记录,编辑数据,你要如后所述增加DataSetProvider和ClientDataSet构件。
    如果你需要比SQLConnection的方法提供的数据更为详细的元数据信息,使用数据集构件的SetSchemaInfo方法,该方法有三个参数:SchemaType、SchemaObject和SchemaPattern。SchemaType参数可以取值 stNone、stTables、stSysTables、stProcedures、stColumns、stProcedureParams和stIndexes。这个参数指示了SQLDataSet 构件在它打开时应该包含的信息的类型。当你使用SQL命令或是存储过程从数据表读取数据时,你可以将SchemaType参数的值设置为stNone,其他的取值也会创建相应的数据集。SchemaObject是存储过程或是数据表的名字。SchemaPattern可以使你规定一个过滤数据的SQL模式。例如:如果SchemaType值为stTables而SchemaPattern值为'EMP%',那么,数据集中将只包括以EMP开头的数据表。 

SQLMonitor
    此构件用来帮助你调试你的程序,它监视所有经过SQLConnection构件和数据库之间的SQL命令。你可以将所有的SQL命令记录到一个磁盘文件,也可以编写一段事件处理代码,按你自己的意愿处理这些命令记录。 

数据访问构件
DataSetProvider 
    此构件通过它的DataSet属性与dbExpress数据集构件相连接,为ClientDataSet构件提供数据,从ClientDataSet构件的变化日志文件产生SQL命令以更新数据库。

ClientDataSet
    此构件通过它的ProviderName属性与DataSetProvider构件相连接,从那里获得数据并存放在内存的缓冲区内,记录所有的数据变化,并在DataSetProvider构件使用ApplyUpdates方法时,将变化的日志文件提交给DataSetProvider构件。 

DataSource 
    此构件通过它的DataSet属性与数据集构件相连接,数据集必须是ClientDataSet或是dbExpress的数据集构件之一。本构件为交互显示和编辑数据的数据感知构件提供基本功能。它也可以用来将数据集构件连接到一对多或一对一的关系型模型。 

SQLClientDataSet 
    此构件是一个内建有DataSetProvider 和SQLDataSet的ClientDataSet构件。只需要把它连接到SQLConnection构件,设置DataSet、CommandType和CommandText属性就可以开始使用了。因为它省略了DataSetProvider和SQLDataSet构件的一些少用的特征,它节约了程序的开发时间,但提供了对单表数据读取的完整的功能。 

    三 MyBase:本地XML数据库 
    包含在ClientDataSet中的数据可以以二进制或是XML格式存盘或从磁盘上读取。这使得ClientDataSet具备如一个单用户关系型数据库系统。唯一的限制是在操作这些数据时,数据必须是在内存里。这很有用,它使你能够开发手提箱式的应用程序,用户可以使用手提电脑从数据库服务器上检取数据并把它存为本地数据,然后从网络上断开,插入、删除和更新数据,存盘且更改日志文件,再联网对数据库更新这些变化。你也可以利用该功能输入或输出XML数据。最后,你可以使用ClientDataSet作为一个高效的临时内存数据表,可以随时创建和删除。 

四 建立数据库应用程序 
    dbExpress和DataCLX真正强大的地方在于你创建复杂数据库应用程序时的高速度。现在假设要建立一个简单的应用程序,要使用户能查看和编辑在部门和雇员之间的一对多的关系,且能按工作级别的降序排列所有的雇员。我们下面一步一步地描述创建该程序的过程,下图显示了数据模块所需要的所有构件。 
(图略)
    从Kylix的File菜单中选New以创建一个新的工程项目,双击对象面板中的数据模块以加入到你的工程。 

数据库连接
    将SQLConnection构件放在你的数据模块的左上角后,用右键单击,选择编辑属性。增加一个新的连接,选择你所用数据库的驱动程序,设置数据库的路径,设置所有你要对缺省值进行修改的属性。最后设置名字为sconEmployee。 

添加数据集构件
    增加两个SQLDataSet构件到数据模块。将它们的SQLConnection属性都设置为sconEmployee。将第一个的名字设置为sdsDepartment且将SQL属性设置为Select * From Department。增加一个DataSource构件,将它的名字设置为srcDeptLink且将它的DataSet属性设置为sdsDepartment以使它能够连接到sdsDepartment。选择第二个数据集构件,设置它的名字为srcEmployee且将它的SQL属性设置为Select * From Employee Where DEPT_NO=:DEPT_NO,再设置它的DataSource属性为srcDeptLink。这告诉sdsEmployee数据集从sdsDepartment的当前记录的DEPT_NO字段获取DEPT_NO参数的值。 
    增加一个DataSetProvider构件,设置名字为provDepartment,设置DataSet属性为sdsDepartment。增加两个ClientDataSet构件,命名第一个为cdsDepartment,设置ProviderName属性为provDepartment,命名第二个为cdsEmployee。右键单击cdsDepartment,选择字段编辑并选择所有的字段。注意最后一个字段叫做sdsEmployee,这是一个嵌套的数据字段,它包括了与部门记录关联的雇员记录。现在选择cdsEmployee构件,并设置它的DataSetField属性为sdsEmployee,它将显示从sdsEmployee字段得到的数据。 
    接着,增加两个DataSource构件,分别命名为srcDepartment和srcEmployee,并分别设置它们的DataSet属性为cdsDepartment和cdsEmployee。这样,所有的处理部门和雇员之间一对多关系的构件就都设置好了。

浏览所有的雇员 
  下一步是添加能够提供所有雇员记录视图的构件。拖拉一个SQLClientDataSet构件到数据模块并设置它的名字为scdsEmpAll,设置DBConnection属性为sconEmployee,设置CommandText属性为“Select * From Employee Order By JOB_GRADE DESC”。既然用户不会更改数据,你可以设置ReadOnly属性为true。
  添加一个DataSource构件,命名为srcEmpAll而且设置它的DataSet属性为scdsEmpAll。这就足够了!由于这个数据集没有与其他构件连接,你可以充分利用SQLClientDataSet构件的各种长处。 

出错处理
  处理数据库更新出错的最简单的方法是使用ReConcile Error对话框。从菜单中选择File|New,单击对话框页,然后双击ReConcile Error对话框以加入到你的工程项目。单击工具栏上的存盘按钮,将它存盘为RecErrF.pas。 

增添代码
    单击数据模块的空白区域,然后单击对象观察器的Events 页。双击OnCreate事件的编辑框以开始编写事件处理程序,添加以下代码以打开三个数据集: 
     cdsDepartment.Open; 
     cdsEmployee.Open;
     scdsEmpAll.Open; 
    从菜单中选择File|Use Unit,再选择RecErrF单元,调用Reconcile Error Dialog方法。选择cdsDepartment数据集构件然后双击OnReconcileError事件,并添加以下代码: 
     Action:=HandleReconcileError(DataSet,UpdateKind,E);
    同样对cdsEmployee数据集构件进行以上处理。这段代码在你更新数据库产生错误时将调用ReConcile Error对话框。   

构造用户界面
(图) 
    为了构造上图所示用户界面,先放置一个PageControl构件在你的窗体上,设置Align属性为alClient,右键单击它并两次选择“新页”以增加两个TabSheet,将它们的标题分别设置为Employee By Dept和All Employee。 
回到Employee By Dept页,在上面添加一个Button、两个DBNavigator和两个DBGrid构件。选择菜单File|Use Unit并选数据模块,点击第一个DBNavigator且按住shift键点击第一个DBGrid,这样同时选中两个构件,在对象观察器中设置它们的DataSource属性为srcDepartment,以同样方法设置另一对构件的DataSource属性为srcEmployee。

添加数据更新递交请求的代码 
    选择按钮构件设置它的标题属性为Apply Updates,双击它创建OnClick事件的代码:
     with dmMain.cdsDepartment do 
        begin 
          if ChangeCount>0 then
             ApplyUpdates(0); 
        End; 
    这段代码检查ClientDataSet的ChangeCount属性,以确定是否有数据的变化要递交给数据库。如有,调用ApplyUpdates方法。参数指明了在更新进程停止之前允许发生错误的数目。
    很重要的一点是你不必调用cdsEmployee的ApplyUpdates方法。既然雇员记录是嵌入在部门数据集中的,它的DataSetProvider会同时处理两个表的更新。在需要先向雇员数据表后向部门数据表进行数据更新时,DataSetProvider构件会知道这样依次递交数据更新请求以保证数据的完整性。 

这意味着什么?
    我们展示这个程序的开发的重要意义并不在于它能做什么,而是在于说明一个比较熟练的Kylix开发者能在30分钟之内开发出一个完整的C/S数据库应用程序。这对于Linux平台上的程序开发是一个巨大的进步! 

原作者:Bill Todd
译者:[email protected] 


[关闭][返回]