荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: PowerBuilder应用开发系列讲座
发信站: BBS 荔园晨风站 (Thu Jan 21 22:39:51 1999), 转信


为下拉式数据窗口建立缓冲区
许多最终用户在使用PowerBuilder应用程序时抱怨运行速度太慢。
一般来讲,一个企业级的客户/服务器应用程序执行速度的瓶颈并不在
于代码执行的效率,而在于应用向后台数据库查询数据时等待后台响
应的时间。改进应用软件速度的关键在于减少应用向后台数据库查询
的数据量,减少网络的数据流量,其中减少下拉式数据窗口的查询量就
是一个有效的方法。
    一般情况下,为了用户输入方便和避免废键,在数据窗口的某些数
据列使用下拉式数据窗口是程序员经常采用的方法。运行一个应用,
某一段时间所处理的一般都是相同或相近的事务,这样同时打开的不
同窗口和数据窗口却很可能同时采用相同的下拉式数据窗口。在显示
这些窗口前,当系统执行主数据窗口的Retrieve()命令时,总是要首先
到数据库中查询这些下拉式数据窗口的数据。如果我们能够减少这些
查询,进而减少网络流量以及后台数据库服务器进行语法分析、设计
查询算法和执行查询的时间,将能使应用的性能得到较大提高。这里
我们采用的方法是在客户端建立一个保存结果集的缓冲区,并利用Sha
reData函数使缓冲区的数据同下拉式数据窗口的主缓冲区建立共享。
    我们将这个数据缓冲区建立在一个不可视的窗口上,在这个窗口
中为每一个不同的结果集创建一个不同的用户对象。首先我们创建一
个标准的不可视的用户对象,在可选的对象类型中选择DataStore,我
们并不需要为这个用户对象编写任何代码,只要将其保存为u_dsa即可

    我们创建一个窗口w_resultset_server作为结果集服务器,在这
个不可视的窗口中声明这样一些实例变量:
    //缓冲区大小
    PROTECTED integer ii_cache_size
    //缓冲区
    PROTECTED  u_dsa  ids_cache[]
    //我们用以检索结果集的事务对象
    PROTECTED transaction i_trans
    //更新结果集的时间(设为30秒)
    PROTECTED long il_refresh_interval = 1800
    //更新的起始时刻
    PROTECTED time itm__last_refresh
    使用dddw的窗口将通过fw_share_dddw()函数来访问w_resultset
_server窗口,这个函数将接受一个数据窗口和一个列名作为参数。
    //public function integer fw_share_dddw
    //参数: DataWindow  adw_parent
    //string  as_column_name  表现形式为dddw列名
    integer  li_cache_idx
    DataWindowchild dwc
    string   ls_dataobject_name
    //dddw所使用dataobject的名称
    ls_dataobject_name = adw_parent.Describe( as_column_name
+ ".dddw.name" )
    IF ls_dataobject_name = "" THEN RETURN 0
    // 该dataobject是否存在缓冲区中
    li_cache_idx = fw_find_dataobject (ls_dataobject_name)
    IF li_cache_idx < 1 THEN RETURN 0
    // 同子数据窗口共享数据
    adw_parent.GetChild ( as_column_name, dwc )
    RETURN ids_cache[li_cache_idx].ShareData (dwc)
    在这个函数中,为确定下拉式数据窗口所使用的数据窗口的名称,
首先使用了Describe( )函数来获得该列的dddw.name属性。如果该列
名没有找到,或该列的表现形式不是下拉式数据窗口,这个函数的返回
值为"";接下来调用fw_find_dataobject()函数,以确定这个数据结果
集是否在缓冲区中,如不存在,就新创建一个;最后使用ShareDate()函
数将缓冲区中结果集同下拉式数据窗口共享数据。
    这个函数中调用的fw_find_dataobject()函数如下:它接受一个a
s_dataobject参数,并使用DO...WHILE循环在缓冲区中查找该对象的
结果集,如找到将lb_found设为True,否则设为False。
    //protected function integer fw_find_dataobject
    //参数: string  as_dataobject
    integer  li_cache_idx = 1
    boolean  lb_found = FALSE
    u_dsa    lds_new_entry
    //定位dataobject所在的缓冲区
    DO WHILE (NOT lb_found) and (li_cache_idx <= ii_cache_si
ze)
       IF ids_cache[li_cache_idx].dataobject = as_dataobject
THEN
         lb_found = TRUE
       ELSE
         li_cache_idx ++
       END IF
    LOOP
    // 如果该dataobject不存在于缓冲区中,则创建一个新入口
    IF NOT lb_found THEN
       IF OpenUserObject (lds_new_entry) < 1 THEN
         RETURN 0
       END IF
       lds_new_entry.dataobject = as_dataobject
       IF lds_new_entry.SetTransObject (i_trans) < 1 THEN
         RETURN 0
       END IF
       IF lds_new_entry.Retrieve () < 0 THEN
         RETURN 0
       END IF
       ii_cache_size ++
       ids_cache[ii_cache_size] = lds_new_entry
       li_cache_idx = ii_cache_size
    END IF
    RETURN li_cache_idx
    如果该数据对象不存在于缓冲区中,我们将使用OpenUserObject(
)函数新创建一个用户对象,并将这个DataStore的DataObject属性赋
值为as_dataobject,然后调用SetTransObect ()函数和Retrieve()函
数查询结果。
    在这个隐含窗口的Open事件中键入下列代码:
    i_trans = sqlca
    itm_last_refresh = Now ()
    //设置起始时间
    Timer ( 60 )
    在窗口函数fw_find_dataobject()中调用SetTransObject()时使
用的事务变量是i_tra ns,这样做的目的是为了使软件更为通用。我
们在Open事件中将这个实例变量赋值为SQLA,您也可以根据需要给予
不同的赋值。我们使用了一个实例变量itm_last_refresh作为计时器
, 并且设定每一分钟中断一次,以使窗口根据不同的需要更新缓冲区
中的数据。
    下面的一个窗口函数fw_refresh_all用以更新缓冲区数据:
    //public  subroutine  fw_refresh_all ()
    integer  li_cache_idx
    // 更新所有缓冲区
    FOR li_cache_idx = 1 TO ii_cache_size
       ids_cache[li_cache_idx].Retrieve ()
    NEXT
    //重新设置更新缓冲区的时间
    i_tm_last_refresh = Now ()
    我们在w_resultset_server的Open事件中对一个计时器进行了初
始化,同时还初始化了一个计时变量itm_last_refresh,下面的工作就
是在Timer事件中编写根据设定的时间来调用fw_refresh_all()的代
码。
    time  ltm_current_time
    integer  li_cache_idx
    //当前时间
    current_time = Now ()
    //考虑过午夜的特殊情况
    IF ltm_current_time < itm_last_refresh THEN
    fw_refresh_all ()
    //检测已过的时间间隔
    ELSEIF RelativeTime ( itm_last_refresh, ii_refresh_inter
val ) <= ltm_curren t_time THEN
    fw_refresh_all ()
    END IF
    一般在一个大型应用中,这个对象中往往要有几十个结果集。开
发者可能并不希望系统同时更新所有的数据,故可以修改Timer事件中
的代码,使系统根据一定的算法,轮流更新缓冲区中的数据,而不使用
户感觉到延迟。值得指出的是,在一般的数据窗口中的dddw,除了在创
建时系统会自动对该数据窗口中的所有dddw进行Retrieve()以外,在
运行过程中如果没有程序明确指明某个dddw执行Retrieve()函数,系
统是不会自动更新其数据的。因此采用本文推荐的方法还可以保持下
拉式数据窗口中的数据接近后台服务器中的最新数据。如果在应用中
必须使下拉式数据窗口中的数据为后台的最新数据,也可以调用wf_re
fresh_resultset(强制缓冲区更新数据,使用的参数有两个:数据窗口
名称和列名,代码如下:
    //public  function  boolean  fw_refresh_resultset()
    //参数: DataWindow  adw_parent
    //string  as_column_name  数据窗口中为dddw的列名
    integer  li_cache_idx
    string   ls_dataobject_name
    //dddw所使用dataobject的名称
    ls_dataobject_name = adw_parent.Describe( as_column_name
+ ".dddw.name" )
    IF ls_dataobject_name = ""THEN RETURN False
    //该dataobject是否存在缓冲区中
    li_cache_idx = fw_find_dataobject (ls_dataobject_name)
    IF li_cache_idx < 1 THEN RETURN False
    //更新缓冲区内的数据
    ids_cache[li_cache_idx].Retrieve()
    RETURN True
    在这段代码中,我们首先使用fw_find_dataobject函数找到要更
新数据的dddw所使用的缓冲区,然后更新该缓冲区的数据即可。

--
※ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店