基于DM数据库的“Power Builder“程序开发

来源:岁月联盟 编辑:zhuzhu 时间:2008-02-02

PowerBuilder是一个优秀的数据库应用前端开发工具,完全支持客户机/服务器(Client/Server)体系结构,全面采用面向对象技术,操作使用极为方便,且富有效率。在使用PowerBuilder开发数据库应用程序时,如何正确地建立与各种数据库的连接是一个十分要害的问题。本文列举各种PB能在DM数据库上所实现的所有数据库相关操作,介绍基于DM数据库的PB程序开发。

一、PowerBuilder数据库接口

PowerBuilder具有极其强大、异常灵活的数据库连接与访问能力,这也是其一贯所拥有并保持领先的传统优势。PowerBuilder提供了对ODBC(Open Database Connectivity,开放式数据库互连)通用标准接口的全面支持。通过ODBC接口,PowerBuilder可以十分方便地连接到目前流行的种类繁多的数据库治理系统(DBMS)或其它数据源。此外,对于目前常用的各种大型数据库治理系统,如Oracle、Informix、Sybase、MS SQL Server等,PowerBuilder也提供了相应的高效的专用接口。数据库不同,或者数据库的版本不同,所使用的专用接口也不同。通过专用接口,PowerBuilder可以更快速、更直接地连接与访问这些大型DBMS,并充分发挥其治理与性能上的优势。

PowerBuilder的数据库接口实际上就是PowerBuilder所提供的一些动态链接库文件.DLL。由于PowerBuilder开发人员的要求各有不同,PowerSoft为不同的PowerBuilder版本(包括各种32位或16位不同语言的版本)引入了不同的文件命名方案。对我们来说,在Windows环境下,PowerBuilder 5.0为PB□□□050.DLL,PowerBuilder 6.0/6.5为PB□□□60x.DLL,PowerBuilder 7.0为PB□□□70x.DLL,其中"□□□"为用于唯一标识某种数据库接口的三个字母的标识,"x"为代表系统平台的字母(假如是16位平台,如Windows 3.x,此字母为"W";假如是标准的32位Windows平台,如Windows 95/98或Windows NT,则不包含此字母)。

二、PowerBuilder事务对象

由于PowerBuilder是一种数据库前端开发工具,因此在进行开发时首先要知道后台数据库的一些信息,如:所使用的数据库治理系统、数据库用户的账号和口令等等。只有获得这些相应的正确的信息,PowerBuilder及应用程序才能正确地与指定的数据库相连,并进一步对其进行有关的数据存取操作。但是,如何才能得到连接数据库所需要的最基本的信息呢?在PowerBuilder中,系统提供了一种不可见的对象,称为事务对象(Transaction Object)。事务对象驻留在内存中,是PowerBuilder最重要的对象之一,用于提供与数据库连接所需要的基本信息(即连接参数)并从数据库获取相应的反馈数据(即状态信息)。PowerBuilder与应用程序主要通过事务对象来实现与各种数据库的连接,但一个事务对象只对应于一个连接,假如应用程序要连接多个数据库,可为每个连接创建一个相应的事务对象。在PowerBuilder与应用程序中,不管是用嵌入式SQL语句还是用数据窗口对象访问数据库,都要使用事务对象。事务对象其实就是程序和数据库之间的桥梁,是程序和数据库之间的一个通信区。

每个事务对象都有15个属性,其中10个用于提供数据库所需要的连接信息,另外5个用于接收每个数据库操作成功与否的状态信息(即SQL语句的运行信息)。

PowerBuilder在启动应用程序时,会自动为其创建一个缺省的全局事务对象SQLCA(SQL Communication Area,SQL通讯区),该对象在应用程序的任何地方都可以访问。假如应用程序只与一个数据库打交道(实际上大多数应用程序都是这种情况),那么直接使用SQLCA也就足够了。同时,使用SQLCA也有好处,那就是无需对其进行事务对象的说明、创建或删除操作,PowerBuilder会自动处理这一切。

假如要使用SQLCA以外的其它事务对象,如DMSQLCA,在创建该对象之前必须先对其进行说明(与其它变量说明相似,事务对象变量可以是局部的、实例的、共享的或全局的):Transaction DMSQLCA

然后使用Create语句完成创建工作:DMSQLCA =Create transaction

创建成功后,DMSQLCA事务对象即可投入使用。当不再使用新创建的事务对象时,应使用Destroy语句及时将其删除掉,以释放其所占用的内存空间: Destroy DMSQLCA

三、数据库连接程序的设计

为使PowerBuilder应用程序能正确地与数据库或数据源进行连接,必须正确地设置应用程序 所使用的事务对象(如SQLCA)的连接属性。作为最基本、最轻易实现的一种方法,可根据应用程序所连接的数据库及所使用的数据接口的具体情况,直接将所需要的连接参数赋给相应的连接属性。如:通过SQLCA与名为dm的ODBC数据源连接,用户名为SYSDBA,口令为SYSDBA,则相应的赋值语句为:

SQLCA.DBMS="ODBC" SQLCA.AutoCommit=FALSE SQLCA.DBParm = "ConnectString='DSN=dm;UID=SYSDBA;PWD=SYSDBA'"(这里要使用至少具有建表权限的用户,因为PB初次连接一个数据库,会在其上建立五张系统表,假如没有相应权限会失败。) connect using SQLCA;

这种直接赋的方法(或称硬编码方式)虽然简单,但其缺点也很明显,假如所使用的数据库或数据接口发生改变,就不得不修改相应的语句来改变连接参数。因此,最好能够通过一种适当的方法为应用程序提供连接参数,一方面可以根据实际情况随意地修改连接参数,另一方面当参数改变时又可以避免修改程序的麻烦。因篇幅所限、该内容忽略。

综上所述,数据库连接程序的设计要点总结如下:

(1)利用PowerBuilder的数据库配置画笔生成相应的设置文件(初始化文件)。这种方法既易于实现,又可充分保证设置文件的正确性、规范性、全面性与灵活性。需要注重的是,为避免不必要的麻烦,确保应用系统能正常运行,设置文件中DBMS的设置值最好不要随意进行改动。

(2)在登录窗口的Open事件中使用ProfileString()函数与ProfileInt()函数从设置文件中读取有关的连接参数。PowerBuilder提供有一个SQLCA.SRC文件,其内容就是实现对事务对象属性的通用赋值的语句,可直接加以利用,先将其插入到应用程序中,再进行适当的修改即可。

(3)为保证系统的安全,用户名与口令由使用者在登录窗口中通过输入动态提供。

(4)在应用程序中可设计一定的"用户治理"功能,对用户的合法性进行认证,并进行相应有权限设置,进一步增强系统的安全性。

四、数据库操作

1、嵌入式SQL语句

PB脚本中可以直接使用嵌入式SQL与DM通信,PB中的嵌入式SQL语句分为静态语句和动态语句,一般情况下可使用静态的sql,动态的sql一般在静态的sql无法满足的情况下或需要更多的灵活性的情况,考虑使用,如数据定义,表名作为变量传递时,或者条件列名不确定等情况。

例如程序开启阶段添加代码,需要完成假如不存在pbdm这张表即建立该表,可用以下动态SQL实现:

int ls_tag,i;select count(*) into :ls_tag from sysdba.systables where name = 'pbdm';if ls_tag = 0 thenexecute immediate 'create table pbdm (a bigint,b binary,c bit,d blob,e char,f clob,g date,h decimal,i double,j float,k integer,l smallint,m time,n timestamp,o tinyint,p varbinary,q varchar)';end if

需要给该表添加100条记录,使用静态sql,例如:

int tempselect max(a) into :temp from pbdm;if isnull(temp) then temp=0;temp=temp 1;long ifor i = temp to temp 100insert into pbdm values (:i,'a',0,'sgsdg','w','sgsdg',sysdate,34634,34634,34634,34634,3464,curtime,curtime,34,'a','2');st_2.text=string(i)nextcommit;

2.数据窗口和数据存储

数据窗口(DataWindow)是PowerBuilder提供给开发人员快速建立基于数据库应用程序的最强有力的工具,也是PowerBuilder与其他面向对象的数据库应用前端开发工具的最主要的区别。它的本质是以自动化的用户/数据库接口为开发人员最大限度地节省时间和精力,并且这种自动化特性并不限制开发人员的主观能动性,开发者能以他所钟爱的方式来应用数据窗口,开发出高质量的应用程序。精通PB者就必定精通数据窗口技术。

数据存储(DataStore)可以看作数据窗口的不可视版,除了不可见,其他功能和数据窗口完全一样,为提高效率使用。

因DM程序员手册已有相关简单介绍,且数据窗口内容相当琐碎,这里不再作更深入研究。

3.PB中的SQL提交方式

在pb中,可以使用sqlca.autocommit = true将自动提交开启,或sqlca.autocommit = False关闭自动提交,需要注重的是,DDL语句为隐性自动提交,不可rollback。

4.PB中对存储过程的使用

以要害字RPCFUNC声明存储过程

(1)在前台要申明一个事务(transact)的用户对象,比方说:u_trans

(2)然后用u_trans取代默认的transact

(3)然后将你要使用的存储过程作为外部的函数引进来

以下为使用PB调用DM中的存储过程的示例(针对DM的几种存储过程分类,分为输入参数过程、输出参数过程、输入输出参数过程):

DM中执行建表和存储过程语句:

--建表create table pbdm (a bigint,b binary,c bit,d blob,e char,f clob,g date,h decimal,i double,j float,k integer,l smallint,m time,n timestamp,o tinyint,p varbinary,q varchar);--输入参数过程create or replace procedure proc_in (b binary,c bit,d blob,e char,f clob,g date,h decimal,i double,j float,k integer,l smallint,m time,n timestamp,o tinyint,p varbinary,q varchar)astemp integer;beginselect isnull(max(a),0) into temp from pbdm;temp:=temp 1insert into pbdm values (temp,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q);end;--输出参数过程create or replace procedure proc_out(a1 in int , b1 out binary , c1 out bit , d1 out blob , e1 out char , f1 out clob , g1 out date , h1 out decimal, i1 out double , j1 out float , k1 out integer , l1 out smallint , m1 out time , n1 out timestamp , o1 outtinyint , p1 out varbinary , q1 out varchar ) as temp integer ;begin select b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q into b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,o1,p1,q1 from pbdm where pbdm.a = a1 ;print 'hi' ;end--输入输出参数过程create or replace procedure proc_inout(a1 in out int , b1 in out binary , c1 in out bit ,d1 in out blob , e1 in out char , f1 in out clob , g1 in out date , h1 in out decimal, i1 in out double , j1 in out float , k1 in out integer , l1 in out smallint , m1 in out time , n1 in out timestamp , o1 in outtinyint , p1 in out varbinary , q1 in out varchar ) as temp integer ;begin select b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q into b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,o1,p1,q1 from pbdm where pbdm.a = a1 ;print 'hi' ;end

(1)在PB在用户对象画笔中创建一个Class-Standard类型的,从Transaction继续的用户对象。另存为uo_sql

(2)在此用户对象中,声明Local External Functions,将存储过程以RPCFUNC要害字声明为外部函数。在Declare Local External Functions对话框中按Procedures按钮选择要调用的后台存储过程,或直接输入语句:

subroutine PROC_OUT(long A1,ref blob B1,ref boolean C1,ref blob D1,ref string E1,ref string F1,ref date G1,ref decimal H1,ref double I1,ref double J1,ref long K1,ref long L1,ref time M1,ref datetime N1,ref long O1,ref blob P1,ref string Q1) RPCFUNC   subroutine PROC_INOUT(ref long A1,ref blob B1,ref boolean C1,ref blob D1,ref string E1,ref string F1,ref date G1,ref decimal H1,ref double I1,ref double J1,ref long K1,ref long L1,ref time M1,ref datetime N1,ref long O1,ref blob P1,ref string Q1) RPCFUNC

 

(3)保存该用户对象。

(4)在Application画笔中,进入应用属性对话框,在Variable Types页,将上Transaction用户对象设置为缺省的全局变量SQLCA。

(5)脚本中,编码调用相应的外部函数。形式:SQLCA.函数名(参数)。如可用“sqlca.proc_out(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)”调用例子中定义的PROC_OUT存储过程。其中a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q为调用参数。

以DECLARE PROCEDURE语句声明存储过程

直接使用以下脚本即可调用

declare proc_ini procedure for proc_in('a',0,'sgsdg','w','sgsdg',sysdate,34634,34634,34634,34634,3464,curtime,curtime,34,'a','2');//`g',g=sysdate,h=34634,i=34634,j=34634,k=34634,l=3464,m=curtime,n=curtime,o=34,p='a',q='2';

execute proc_ini;

两种方法的区别:

(1)方法一适用于具有IN、OUT和IN OUT参数的存储过程,而方法二仅支持IN和OUT参数,不支持IN OUT参数;

(2)方法一对参数的数目无限制,方法二最多支持255个参数;

(3)方法一不支持记录(Recorder)的传递,方法二可传递和接收记录。

5.PB中对事务的使用

PowerBuilder中,有4个SQL语句专门进行事务处理,它们是connect,disconnect,commit和rollback,分别负责和数据库建立联接、断开联接、提交事务和回退事务等。在进行数据窗口检索或者执行SQL语句之前,首先应该使用connect语句和数据库建立正确的联接;当所有和数据库相关的操作完成后,可以使用disconnect语句和数据库断开联接。commit用来提交一个事务,rollback用往返退一个事务。这四个事务治理语句的格式相类似,如下所示:statement {using transaction};和数据库建立联接后,可以完成操作数据库的工作并执行commit或rollback。在每个commit或rollback之后关闭旧的事务处理,并开始新的事务处理。在一个事务处理过程中,应用程序控制着数据库,并由DBMS根据一定的机制对数据库中的数据加锁。假如一个事务的持续时间过长,就会导致许多的问题。例如,对于一个典型的生产系统,天天将自动或者人工进行事务日志转储。假如该系统的某类客户端应用程序整天运行并且只进行只读查询,那么在使用connect语句启动事务之后事务总是处于激活状态,任何转储或者截断日志的企图都不会生效,最终将导致日志爆满而引起整个数据库的问题。所以,PowerBuilder给事务对象提供了一个可以选择自动提交事务的成员变量,即AuToCommit,将该参数设置为True可以在事务对象所包含的每个语句执行完后自动执行commit,从而结束一个事务。另外一种解决方法是由开发人员在脚本中使用事务治理语句显式地治理事务,这需要更好地理解事务。

数据窗口是和数据库打交道的一个主要控件,在执行数据窗口的功能之前必须首先给数据窗口控件正确设置事务对象。一般在数据检索之前使用函数SetTrans或SetTransObject设置事务对象。使用不同的函数,数据窗口的事务处理方式就不同。函数SetTrans的语法格式如下所示:dwcontrol.SetTrans( transaction )其中,dwcontrol是要设置的事务对象的数据窗口控件名称,transaction是事务对象名称。若函数正确执行,则返回1,否则返回-1;任意参数为NULL则返回NULL。函数SetTransObject和该函数的格式、参数与返回值完全相同。

函数SetTrans设置事务对象后,数据窗口可以自动治理事务的处理,事务中所包含的每个功能或者语句执行完后都自动进行事务治理。而函数 SetTransObject设置事务对象后,数据窗口的事务处理得由脚本控制,除非在和数据库建立联接之前将事务对象的AuToCommit成员变量设置成了True。虽然数据窗口自动进行事务处理可以省去一些关于事务处理的脚本,但是也带来了很多的潜在危险。每次执行检索或修改等操作之前自动联接数据库,执行完后自动执行disconnect,无需再执行connect,commit,rollback或disconnect了。执行过程中的任何错误都会导致自动执行rollback,脚本对事务处理别无选择,无法控制事务的处理。在应用系统中和数据库的联接非常少时,可以由系统自动进行事务处理,这时使用函数SetTrans给数据窗口控件设置事务对象。通常情况下,使用SetTransObject设置事务对象可以使数据窗口有更高的执行效率。建议使用SetTransObject给数据窗口控件设置事务对象,例如,在数据窗口dw_dm的constrator或新建按钮中输入脚本:

dw_dm.settransobject(SQLCA) dw_dm.retrieve()