闲来无事,今天休息,放点资料上来活下人气!2(转)

liaolwj 2003-09-04 10:04:12
还要遵循以下规则:
1. 远程对象不能为自动生成对象,而只能使用CREATE来生成。
2. 远程对象的公有函数的参数不能为指针。
3. 远程对象的公有函数的参数的类型可能为PowerBuilder支持的所有简单类型和结构,但不能为PowerBuilder内部对象如DATASTORE。
4. 远程对象的公有函数的参数可以为用户自定义的不可视对象。
5. 上述对参数的描述同样适应于返回值。
6. 远程对象的公有函数中不能包含有对可视对象操作的代码。
只要是符合上述条件的用户自定义不可视对象,都可以作为应用服务器的服务的提供载体,客户端程序可以通过远程对象代理来调用这些对象的函数或使用其成员。
定义应用服务器的服务实际上就是在服务器应用中定义远程对象。
2.3.2客户端程序存取应用服务器提供的服务
客户端程序是通过远程对象代理来存取应用服务器提供的服务的。所谓远程对象代理,就是具有远程对象所有公有成员和函数定义的对象,它描述了远程对象所能提供的服务。我们可以使用PROXY类型的工程来生成远程对象的相应远程对象代理。
如有远程对象代理uo_timeserver 含如下成员函数:function datatime getdate(),在客户端如何调用此函数呢?如下:
//客户端接口对象为 g_connection
uo_timeserver timeserver //定义一远程对象代理对象
g_connection.CreateInstance(uo_timeserver) //建立远程对象实例
messageBox(‘服务器时间’,uo_timeserver.getdate()) //调用远程对象的函数
注意,上面MessageBox显示的时间是服务器的时间。如上所述,我们归纳出客户端调用应用服务器的服务的步骤如下:
1. 定义相应的远程对象代理对象
2. 调用客户端接口对象connection的CreateInstance函数建立远程对象实例
3. 通过远程对象代理对象调用远程对象的函数或存取其数据成员
2.3.3了解应用服务器的会话
现在我们已经知道该怎样建立应用服务器、怎样通过应用服务器提供服务了;也知道怎样在客户端程序来使用这些服务。思考如下代码:
在应用服务器端应用的OPEN事件中:
//设置好SQLCA的各项属性
。。。。。
connect using sqlca;
在应用服务器端有一远程对象,其中有一段代码:
datastore dsUser
dsUser = create datastroe
dsUser.dataobject=’dw_user’
dsUser.SetTransObject(sqlca)
dsUser.Retrieve()
MessageBox(‘信息’,dsUser.RowCount())
在预览dw_user数据窗口时,共有100行数据,那么上述代码运行结果如何呢?结果显示,dsUser.RowCount() = 0 !
原来,每当一个客户端程序与应用服务器建立一连接时,应用服务器即为此连接启动一独立的会话(SESSION),此会话具有如下特点:
...全文
37 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
liaolwj 2003-09-04
  • 打赏
  • 举报
回复
并发控制
并发能力是指多用户在同一时间对相同数据同时访问的能力。一般的关系型数据库都具有并发控制的能力,但是这种并发功能也会对数据的一致性带来危险。试想若有两个用户都试图访问某个银行用户的记录并同时要求修改该用户的存款余额时,情况将会怎样呢?我们可以对PowerBuilder中的DataWindow进行设置来进行并发控制。所谓并发控制就是指在用户数据修改的过程中保证该数据不被覆盖或改变的方式,在下面的例子中我们将看到如何设置Da taWindow来控制开发访问。为了说明问题,我们举这样一个简单的银行系统中的例子,某用户的存款状况如右:

我们假设事情的经过是这样的:公司的某员工在银行前台取款2,000元,银行出纳查询用户的存款信息显示银行存款余额20,000元;正在这时,另一银行帐户转帐支票支付该帐户5,0 00元,机器查询也得到当前用户存款20,000元,这时银行的出纳员看到用户存款超过了取款额 ,就支付了客户2,000元并将用户存款改为18,000元,然后银行的另一名操作员根据支票,将汇入的5,000元加上,把用户的余额改为25,000元,那么数据库管理系统是否可以接受这些修改呢?
在DataWindows的设计中,我们选择菜单Rows|Update…,会出现Specify Update Charac teristics的设置窗口,在这个窗口中我们设置Update语句中Where子句的生成,以此来进行开发控制。在这里有三个选项,我们分别看一看在本例中这三个选项的结果:
(1)Key Columns:生成的Where子句中只比较表中的主键列的值与最初查询时是否相同来确定要修改的记录。在上述的例子中,转帐支票的操作将覆盖出纳员作出的修改,这样银行损失两千元。
(2)Key and Updateable Columns:生成的Where子句比较表中主键列和可修改列的值与最初查询时否是相同。在上例中两次查询出的结果都是有两万余额,当第一个人修改余额时 ,余额仍是二万元,所以修改成立,而支票转帐操作时余额已不是二万,所以该列不匹配,修改失败。
(3)Key and Modified Columns:Where子句比较主键和将要修改的列,在本例中,结果与 Key and Updateable Columns的选择相同,因为余额已改变,不再与最初的查询相同,因此仍然不能修改。
让我们作另外一个假设,我们把银行后台作支票转帐操作改为冻结用户存款,即把状态字段的值改为冻结,而且事件发生的次序如下表,那么表中的次序4…前台出纳的修改能不能成立呢:


1.Key Columns:Where子句只比较主键值,显然出纳员的修改是允许的。
2.Key and Updateable Columns:生成的Where子句包括比较所有可修改的列,因此出纳修改时Statue字段为冻结与出纳查询时的tive不符,修改失败,同时显示错误信息。
3.Key and Modified Columns:Where子句的比较包括主键和要修改的列,由于本列中修改列仍为20,000元没有变化,所以出纳的修改可以成立。
在本例中,我们可以看到Key and Updateable Columns的选项最严格,可以避免出现状态列发生改变时余额作修改的错误,但是这也会禁止我们作一些本当允许的并发修改,如出纳修改存款余额,而业务员修改用户的联系地址等。因此我们应当根据实际情况,选择适当的Upd ate设置。
根据我们使用数据库的不同,我们还有一些其他的控制并发访问和修改的选择方案,如对数据加锁。锁是一个用户避免其他用户对指定行作修改的操作。在结束一个事务如执行com mit,rollback,disconnect等语句时自动将锁释放。如果您使用的DBMS支持锁的操作,在Pow er-Builder的DataWindow设计时,Select语句可在from子句中加上with holdlock:即在data Window的SQL Window中,在表窗口的标题处点击右鼠标,弹出菜单的最后一个选项即为Hold lock。选择该项,生成的SQL语句将在re-trievel()函数执行后将所查询的数据加锁,以避免其他用户的修改访问,直至commit,rollback等事件发生后解锁。这种方式带来的问题是,当用户查询完数据后可能离开计算机长时间不用,这段时间内其他用户均无法修改数据。此外有些DBMS如Sybase等不支持行级锁,也就是说当你对某一行查询时更多的行都被上了锁,这就更增加了并发处理的局限性。另一个值得注意的问题是在多窗口应用中某一个窗口的事务提交将会导致使用一事务中其他数据窗口的查询行解锁,这时修改将可能发生错误。某些DBMS 系统支持一个称作"时间戳(timestamp)"的数据项来控制并发性。每张表中都有一个时间戳的数据列,当Insert语句或Update语句对数据行作修改时该列自动被修改为当前时间。当你要作修改时,where子句可检查时间戳列在查询时和修改时两个值是否相符,以此来确保您作出的修改不会覆盖别人的修改,因此这种确认方式与key and Updateable Columns选项相同。即使两个用户对同一行的不同列作修改,后一个修改者也将失败。在常用的关系型数据库中Sybase和Microsoft的SQL Server支持时间戳的使用。而在PowerBuilder中,不管用户后台连接何种数据库,只要表中带有timestamp的列名且数据类型为datetime,PB将自动忽略Upda te characteristics的选项,而在where子句中生成主键和时间戳列的比较。
如果您所用的数据库不支持时间戳但支持触发器,您也可以在表中增加一列整数型的列。当有对表中某种记录作修改时,该列自动加1。下列使用的是Watcom数据库,对Shipper表增加Updcnt字段并作两个触发器,这样任何用户或进程试图修改某行记录时,该字段均可发生变化。
对INSERT触发器的编写如下:
DROP TRIGGER INS—SHIPPER’
CREATE TRIGGER SHIPPER BEFORE INSERT ON SHIPPER
REFERENCING NEW AS Newvalue
FOR EACH ROW
BEGIN
SET newvalue.UpdCnt=newvalue.UpdCnt+1;
END'
同理可编写UPDATE触发器。
在您的PowerBuilder应用之中,除表的主键外,必须再加上这一列作为检测列加入Updat e语句中的Where子句中,这样再作Update操作时,后台数据库会比较修改时与用户作Retriev e操作时数据是否相等,以确认是否能作修改。在DataWindows中在Specify Update Charact eris-tics的对话框的右下角的Unique key column(s)中加上Updcnt一项,同时注意where c lause中选择Key columns,这样PowerBuilder在构造where子句时就会认为Updcnt亦是表的主键,而成为检测项。
当数据窗口的Update函数被调用后,触发器将修改过记录中的Updcnt列表为新值,为保证下一次修改能够有效,您应当立即作Retrieve()以使DataWindow缓冲区中Updcnt的值与数据库相同。显然修改后立即查询的代价要比其他任何一种并
发控制的代价要小得多。
liaolwj 2003-09-04
  • 打赏
  • 举报
回复
一.SharedObjectRegister函数
在调用所有其它函数之前,一定要调用此函数。此函数的功能是在应用服务器上注册了一个共享对象,即:在应用服务器上启动了一个独立会话;在此会话空间中建立一个指定类型的共享对象。
二.SharedObjectGet函数
此函数取得一个已经注册了的共享对象的引用。通过此引用来调用共享对象提供的函数或存取其数据成员。
三.SharedObjectUnregister函数
此函数与SharedObjectRegister函数的功能刚好相反,其功能为注销一注册过的共享对象,即:注销此共享对象;结束与此共享对象相关的会话。

共享对象具有以下特性:
1. 共享对象是一个远程对象,它具有远程对象的所有特性
2. 共享对象运行在一独立的会话中,具有会话的所有特性
3. 共享对象的会话开始于对象的构造事件,结束于其析构事件

TIPS
1. 共享对象的初始化可以放在其构造事件中
2. 共享对象的结束代码可以放在其析构事件中

3.2用户登录应用服务器的控制
客户程序在使用应用服务器提供的服务之前,总是要先连接到应用服务器。在实际应用中,一般情况下都要对连接的用户进行核对,以验证其身份,只有身份合法的用户才被许可连接到应用服务器上。在PowerBuilder中,系统提供了一系统手段来支持这一功能。
3.2.1服务器应用的ConnectionBegin事件
事件的参数:
string userId //客户端用于登录到应用服务器的用户名connection.userid
string password //客户端用于登录到应用服务器的密码 connection.password
string connectstring //其它可以附带的信息 connection.connectString
事件的返回值:
ConnectPrivilege! //普通用户,允许连接
ConnectWithAdminPrivilege! //超级用户,允许连接
NoConnectPrivilege //非法用户,不允许连接
如上所述,我们可以通过参数取得用户名和密码,可以通过返回值来控制是否允许用户登录到应用服务器上,以及用户的身份如何,这样就可以实现我们控制用户登录的目的。
看下列代码:
if userid = ‘Administrator’ and password = ‘system’ then
return ConnectWithAdminPrivilege!
Elseif userid = ‘Guest’ then
Return ConnectPrivilege!
Else
Return NoConnectPrivilege!
End if
3.2.2在线用户监视器
请看下列应用服务器上的代码
//g_connection为客户端接口
//w_monitor为一窗口
//dw_monitor为一外部数据源数据窗口,列为userid,connectid
//w_monitor的open事件
timer(1)
//w_monitor的timer事件
connectionInfo info[]
long userCount,row

userCount = g_Connection.GetServerInfo(info)
dw_monitor.setRedraw(false)
dw_monitor.reset()
for I = 1 to userCount
row = dw_monitor.insertRow(0)
dw_monitor.object.UserID[row] = info[I].connectUser
dw_monitor.object.ConnectID[row] = info[I].clientId
end for

dw_monitor.setRedraw(TRUE)

以上代码即可实现在线用户监视器
liaolwj 2003-09-04
  • 打赏
  • 举报
回复
1. 会话具有单独的地址空间。对于会话来说,其它会话或服务器主会话都是不可见的。
2. 会话生命期从服务器的ConnectionBegin事件开始,到ConnectionEnd事件结束。
3. 会话具有单独的全局对象的拷贝,就是说每一会话都具有其自已独立的全局变量。

如上所述,我们就会知道,会话中的SQLCA对象和应用服务器中的SQLCA变量不同,前面我们所说的代码是不会成功的。
TIPS:
1. 可以在ConnectionBegin事件中初始化会话的全局变量
2. 可以在ConnectionEnd事件中处理会话的结束工作,比如注销动态分配的对象


第三章 深入了解PowerBuilder中的分布式应用体系
本章主要是就PowerBuilder中分布式应用的一些比较高级的问题进行一些讨论,主要涉及到的问题有三个个:
1. 如何在客户端即会话之间进行通迅。
2. 如何控制用户对应用服务器的登录。
3. 异步远程调用及推(PUSH)技术
3.1分布式应用中客户端之间的通迅
在第二章中我们知道,会话之间是相互独立的,采用传统的方法如全局变量来进行会话间通迅是行不通的,还有什么方法呢?
3.1.1文件或是数据库中的表。
步骤如下:
1. 在远程对象中将要交换的数据写入到文件或表中。
2. 远程对角可以在需要的时候从文件或是表中读入需要的数据。
可以看出,使用文件或表来存放会话间共同的数据,实现会话间通迅是可以实现的,但是,它具有以下几个缺点:
1. 需要自已解决会话间并行冲突的问题,决定何时读何时写数据
2. 要进行磁盘读写或网络存取,速度慢,不适合大用户量的应用
最好的方法,当然是在内存在建立一共享内存区。下面介绍的方法就是这种类型。
3.1.2共享对象(SharedObject)
从PowerBuilder 6.0开始,系统提供了一种叫做共享对象的技术,从名称上我们就知道,这种技术提供了一种会话间共享对象的方法。下面讲述在PowerBuilder中怎样使用这一技术:
1. 定义并完成一远程对象(以uo_sharedObject为例),并生成相应远程对象代理
2. 在服务器应用的OPEN事件中加入以下代码:
SharedObjectRegister(‘uo_sharedObject’,’sharedObject’)
3. 在服务器应用的CLOSE事件中加入以下代码:
SharedObjectUnregister(‘sharedObject’)
4. 在客户端程序要使用共享对象的代码处加入:
uo_sharedObject sharedObject
SharedObjectGet(‘sharedObject’,sharedObject)
//调用sharedObject的函数或存取其属性
上述代码都做了些什么呢?其功能的实现主要通过几个函数,下面一一讲解:

1,079

社区成员

发帖
与我相关
我的任务
社区描述
PowerBuilder 相关问题讨论
社区管理员
  • 基础类社区
  • WorldMobile
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧