用XBase开发的程序,在系统老化之后,不应盲目推翻重来,而是要利用新技术把原有资源转化,以适应现在的需求。XBase型数据库比较适合转化成网络数据库。做网络数据库要有前台的应用程序和后台的网络数据库。前台程序的开发平台可以用Delphi,Visual FoxPro和PowerBuilder。后台的网络数据库可以是Novell 的Sybase,WindowsNT 的SQL Server, UNIX的Informix,以及DB/2 for NT等等。
Client/Server模式的突出优点是数据集中化,跨系统信息共享,便于数据管理和维护,但对客户端维护困难的问题,我们在后面提出一个解决方法。客户端与主服务器通过网络以TCP/IP协议连接。客户端可以并发的存取主服务器上的数据。系统管理员可以在主服务器上监视客户的上线情况及数据库的使用情况,做到实时监控。Delphi是Borland(已经更名Inprise)的产品,控件多,比较适合数据库开发。下面用Delphi 3.0 C/S for Win95做前台应用程序,后台采用Windows NT的SQL SERVER 6.5(以下简称SQL服务器)做服务器来说明一个程序的开发过程及注意事项。
一、基本编程原理和步骤 基本原理如图所示
1开发环境
我们在开发Client/Server应用程序时需要两台机器(服务器,一个客户机),但Delphi可以做到单机开发。Delphi的可伸缩性很强,把应用程序由单层过渡到两层,只要简单地把连接的数据集由本机的数据库重新指向SQL服务器即可。像PowerBuild 一样,Delphi也有本地库,这就是InterBase Server,它提供了一个单用户多实例的SQL服务器平台,可以做测试平台。我们在将数据库应用程序转移到对Sybase等远程数据库的访问之前,可以在Local InterBase Server平台建立和测试数据库应用程序。这样可暂时不考虑网络连接,专心致力于解决业务逻辑。当业务逻辑实现后,只要把Database 控件中的Aliasname 改成新的数据源即可将程序扩大到网络环境。大大提高了开发软件的效率,并且降低了开发难度。
2后台建立数据库并创建连接
数据库建立包括安装系统,建库建表,对数据库写触发子和存储过程。
安装时要注意的是要把SQL Server的客户数留到50 以上。否则服务器会在用户多了以后死锁。
SQL Server是图形化的管理,库表的建立非常容易 。我们不提倡直接建立数据库、表格,输入数据。我们采取的方法是利用已有DBF数据库,在Delphi的Database Desktop把DBF转换成SQL Server中的表格。这样XBase开发的程序的资源就不会浪费了。对新表,用FoxBase建表格,输入数据后再转换。具体方法是:先用ODBC建立与SQL Server连接的数据源,用Database Desktop的菜单项TOOLS->UTILITIES->COPY的功能。其实这个工具可以进行异种数据库转换,在本身具有ODBC驱动程序或Delphi的SQL LINK支持的数据库之间任意进行转换。
3.前台程序的基本编程
Delphi与后台数据库的连接可有两种途径,一是ODBC,这是标准,兼容性很好。二是Delphi带的SQL Link,它由Delphi自己开发,速度稍快,但我们在应用中发现SQL Link对有些数据库系统的支持并不是很稳定,如连Informix时,退出时就很容易死机。所以常以ODBC连接数据库。在控制面板的ODBC中需要设置数据源名称,服务器名称(如果不设置登录的数据库名称,就将登录到后台数据库给你这个用户的默认数据库)。
Delphi是快速开发工具(RAD)中最容易上手的。编程一般经过三个步骤:
(1)注册ODBC数据源;
(2)配置BDE;
(3)往FROM 上放置Query/Table,DataSource, DBgrid控件,分别设置控件属性以实现与数据库的连接操作。具体说明如下:
Delphi 涉及数据库编程的控件有两类:
数据显示控件:用来显示数据库内的数据。DBGrid用于全屏显示和编辑数据库表中的记录。数据连接控件:负责掌管数据库的连接。
Database控件是为开发两层数据库应用程序时,设置登录数据库的有关参数。
Query 控件是用来传递SQL语句到服务器上得到一个数据集或执行一个动作。
Datasource控件是连接数据显示控件和数据连接控件的桥梁。
Query控件执行静态SQL语句的写法是:
Query1.SQL.Clear;
Query1.SQL.Add(‘SELECT * FROM databasename ’);
Query1.SQL.Open,
值得一提的是Delphi中还有种动态SQL,可以嵌入变量参数,给编程带来极大方便。
Query1.SQL.Clear;
Query1.SQL.Add('SELECT ks FROM ks WHERE py like :py');
Query1.ParamByName(‘py').AsString:= Edit1.text+‘%'
Query1.Open;
Query控件的执行方法有两种:Open,ExecSQL。Open方式可以打开所联系的数据表格, 得到一个数据集。ExecSQL方式则只是运行SQL语句,并不将运行后的表格送往相连的数据显示控件,所以执行像Update dataname Set ....,Delete ...FROM .. 的动作,就要用ExecSQL。
当应用程序第一次访问SQL数据库,会触发一个自动连接过程。连接过程需要确认访问数据库的权限。如果你要在程序中接受口令,则必须把Database控件的LoginPrompt 属性设为False。
Database1.Params.Add(‘user name='+myusername ); // myusername变量名
Database1.Params.Append(‘password='+mypassword);
Database1.Connected:=true;
关于日期的处理,要不存在2000年问题,只要在Form.OnCreate事件中加上ShortDateFormat:=‘mm/dd/dddd/yyyy';mm :有前导0的月份。dd:有前导0的日期,dddd: 表示这一天是星期几,yyyy:四位年份。此外,在Delphi 中的BDE Aministrator 中的Configuration->System->Formats 中有资料介绍,此方法的可行性尚未得到证实。
二、事务处理 在客户/服务器应用程序中,事务控制用来维护数据一致性。Delphi中提供了事务的隐式和显式方法。隐式控制对写入数据库的数据的每一行都要进行事务控制,导致网络繁忙和程序性能下降;用显式控制能自定义开始、提交和终止事务的过程,因而网络开销小,性能高。
显式控制有两种方法:
1利用Database控件
Database控件用于事务控制的属性是TransIsolation,方法有StartTranstion、Commit和Rollback。标准写法如下:
Databasel.starttransaction;
Try
Query.SQL.Clear; //具体处理
Query.SQL.Add('update databasename set gz=gz+1');
Query.ExecSQL;
Databasel.commit;
Except
Databasel.rollback; //遇异常,回滚
End;
2.直接利用远程SQL服务器的事务处理功能,把SQL语句通过Query控件传递到服务器上。当程序不用本地库时,可以使用这种方法,但要用在BDE将SQLPassThroughMode设置为NOT SHARED。程序中我们可采用如下结构:
IF MessageDlg('确认改标志位?'', mtConfirmation, [mbYes, mbNo], 0)=mrYes then
Begin
DoSQL:=0; //用一个变量做标志
Query.SQL.Clear; // 改状态。
Query.SQL.Add('update .... Set .....)');
While DoSQL=0 do
Try
Query.ExecSQL;
DoSQL:=1;
Except
IF MessageDlg(‘改状态时发生共享冲突,要重试吗 ',
mtConfirmation, [mbYes, mbNo], 0) =mrNo Then Exit;
end;
end;
3减小共享冲突的概率
在实际中还有一种情况也可能引起共享冲突,这就是缓存更新。应用程序往数据库中写数据,先放在本地的缓冲区里然后由BDE提交,这样在多用户情况下就可能发生数据同时由缓存向数据库提交的情况,引起共享冲突。所以对频繁修改的数据要取消缓存更新。
在数据库的应用中,利用临时表也能减小冲突的概率。利用SQL语句可以在服务器上建立临时表,临时表会在使用完后被系统自动删掉。
例如下面语句分别把查询结果和统计结果放入临时表:
SELECT * FROM DatabaseName INTO temp temptable..
SELECT city_id,COUNT(*) lzcount ,SUM(jour_amt) lzsum FROM db_connect
WHERE flag=“2" GROUP BY city_id ORDER BY city_id INTO TEMP tempdatabase'
三、系统优化 1服务器端
要尽可能的把客户端的工作向服务器上移植。在服务器上大量使用触发子预处理程序、完整性约束才能做到真正意义上的瘦客户端。Delphi 可以用Query控件传递SQL语句到服务器端而且可以动态地在服务器端创建存储过程,用StoreProc 控件调用服务器上的存储过程。一些涉及大量记录的工作任务因此可以用存储过程改写。对唯一性字段(身份证号,凭证提交号)可以作为数据库主键,让重复数据不能入库,省去客户端对数据的检测。
下面的例子是利用触发子做数据库RS的更新日志功能:
CREATE TRIGGER updatetrigger ON dbo.rs
FOR update
AS
declare @oldvalue char(20)
SELECT @oldvalue =xm FROM deleted
declare @newvalue char(20)
SELECT @newvalue=xm FROM inserted
insert log values //往LOG表中写。
(‘rs数据库',‘用户'+user_name( ),GETDATE( ),@oldvalue,@newvalue,‘更新')
// User_name( ),GetDate( ) 是SQL SERVER系统函数
2客户端
(1) 客户端禁用Table控件
举例:对数据库的一个字段进行求和,Table 控件的做法是把整个数据集传到客户机上,然后累加。而Query控件则是把SQL语句传到服务器上,由服务器统计出结果。两者相比Query在网络上只传回较少数据,而Table传输的数据较多。
(2)去除无用代码
有时程序中无用的代码占据大量空间。在程序调试过程中,可整理代码。方法是在调试时不用编译或保存,打开File菜单,选择Save File As...,在保存文件对话框中选择Cancel即可去除无用代码。
(3)减少不必要的I/O
要加快客户