请教一下PB的DW.update()

ilearn 2012-03-21 03:35:06
请问PB的dw_1.update() ,这个机制是怎样的?

比如有个表里cli_no是主键 dw 有个字段是cli_no,如果dw_1.update()时pb用insert 的sql语句话就会出错了,所以
pb会不会这么智能?我应该怎样做?
...全文
994 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
yyoinge 2012-03-21
  • 打赏
  • 举报
回复
并发控制

  并发能力是指多用户在同一时间对相同数据同时访问的能力。一般的关系型数据库都具有并发控制的能力,但是这种并发功能也会对数据的一致性带来危险。试想若有两个用户都试图访问某个银行用户的记录并同时要求修改该用户的存款余额时,情况将会怎样呢?我们可以对PowerBuilder中的DataWindow进行设置来进行并发控制。所谓并发控制就是指在用户数据修改的过程中保证该数据不被覆盖或改变的方式,在下面的例子中我们将看到如何设置DataWindow来控制开发访问。为了说明问题,我们举这样一个简单的银行系统中的例子,某用户的存款状况如右:

  我们假设事情的经过是这样的:公司的某员工在银行前台取款2,000元,银行出纳查询用户的存款信息显示银行存款余额20,000元;正在这时,另一银行帐户转帐支票支付该帐户5,000元,机器查询也得到当前用户存款20,000元,这时银行的出纳员看到用户存款超过了取款额,就支付了客户2,000元并将用户存款改为18,000元,然后银行的另一名操作员根据支票,将汇入的5,000元加上,把用户的余额改为25,000元,那么数据库管理系统是否可以接受这些修改呢?

  在DataWindows的设计中,我们选择菜单Rows|Update…,会出现Specify Update Characteristics的设置窗口,在这个窗口中我们设置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的选项最严格,可以避免出现状态列发生改变时余额作修改的错误,但是这也会禁止我们作一些本当允许的并发修改,如出纳修改存款余额,而业务员修改用户的联系地址等。因此我们应当根据实际情况,选择适当的Update设置。

  根据我们使用数据库的不同,我们还有一些其他的控制并发访问和修改的选择方案,如对数据加锁。锁是一个用户避免其他用户对指定行作修改的操作。在结束一个事务如执行commit,rollback,disconnect等语句时自动将锁释放。如果您使用的DBMS支持锁的操作,在Power-Builder的DataWindow设计时,Select语句可在from子句中加上with holdlock:即在data Window的SQL Window中,在表窗口的标题处点击右鼠标,弹出菜单的最后一个选项即为Holdlock。选择该项,生成的SQL语句将在re-trievel()函数执行后将所查询的数据加锁,以避免其他用户的修改访问,直至commit,rollback等事件发生后解锁。这种方式带来的问题是,当用户查询完数据后可能离开计算机长时间不用,这段时间内其他用户均无法修改数据。此外有些DBMS如Sybase等不支持行级锁,也就是说当你对某一行查询时更多的行都被上了锁,这就更增加了并发处理的局限性。另一个值得注意的问题是在多窗口应用中某一个窗口的事务提交将会导致使用一事务中其他数据窗口的查询行解锁,这时修改将可能发生错误。某些DBMS系统支持一个称作"时间戳(timestamp)"的数据项来控制并发性。每张表中都有一个时间戳的数据列,当Insert语句或Update语句对数据行作修改时该列自动被修改为当前时间。当你要作修改时,where子句可检查时间戳列在查询时和修改时两个值是否相符,以此来确保您作出的修改不会覆盖别人的修改,因此这种确认方式与key and Updateable Columns选项相同。即使两个用户对同一行的不同列作修改,后一个修改者也将失败。在常用的关系型数据库中Sybase和Microsoft的SQL Server支持时间戳的使用。而在PowerBuilder中,不管用户后台连接何种数据库,只要表中带有timestamp的列名且数据类型为datetime,PB将自动忽略Update 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应用之中,除表的主键外,必须再加上这一列作为检测列加入Update语句中的Where子句中,这样再作Update操作时,后台数据库会比较修改时与用户作Retrieve操作时数据是否相等,以确认是否能作修改。在DataWindows中在Specify Update Characteris-tics的对话框的右下角的Unique key column(s)中加上Updcnt一项,同时注意where clause中选择Key columns,这样PowerBuilder在构造where子句时就会认为Updcnt亦是表的主键,而成为检测项。

  当数据窗口的Update函数被调用后,触发器将修改过记录中的Updcnt列表为新值,为保证下一次修改能够有效,您应当立即作Retrieve()以使DataWindow缓冲区中Updcnt的值与数据库相同。显然修改后立即查询的代价要比其他任何一种并

发控制的代价要小得多。

不想倒也不觉得,可真的想想似乎好像也不是那么清楚,我的理解大概是这样:

最严格的并发控制:
Key and Updateable Columns + Use Update
对主键和所有可更新列进行检查:有任何一个列在提交时发生了变化即告失败,即阻止事物之间修改同一数据。
直接更新方式:阻止事物内部对主键列进行任何交叉修改(逻辑正确也不行)。

最宽松的并发控制:
Key Columns + Use Delete then Insert
仅对主键列进行检查:允许非主键列数据被不同事物同时修改。
删除后插入方式:允许事物内部对主键列进行逻辑正确的交叉修改。

死锁预防:
不同数据库的锁机制各不相同,但对应用程序来说,造成死锁的最大可能就是:没有养成对每个 COMMIT 的执行结果进行检查的编码习惯,导致提交出错时未能及时 ROLLBACK 造成死锁。



其实就是这么一个过程,在dw update时,他会先检查你所定为key的几列和retrieve时取出的来值是否相同,如果相同则update,不同则报
"row changed between retrieve and update"这个错误
如果出了这个错你会看到在这个错误框里会有个update语句
update 表 set 你所设要更新的列 = :值
where 设定的key = 原来的值;



其实讲了那么多,无非就是这么几种情况:
1、在做报表时设置成:KEY AND MODIFIED COLUMNS && USE UPDATE
2、使用SQL语句: 加上LOCK或 RowLock.
3、记得UPDATE后要COMMIT或ROLLBACK。
4、运用FOCUS或存储过程记得还要CLOSE。

一般来说,要简单的话,记得这样就可以了:
用DataWindow操作的话:
设置DW的Specify Update Characteristics为:
  (3)Key and Modified Columns
这样,只要你更新的列的值没有变,则大家都可以成功,有效的防止了多用户重叠更新的问题,相当安全,不必使用第二选项.

如果是使用SQL语句的话,就要使用事务,这样就能确保你的修改是完整而且不被别人干扰的.而且不必使用上面各位朋友的复杂的方法,就这么简单就可以:
假设有数值dec ldec_new = 2000
sqlca.autocommit=false //一定要设置为不自动提交
string ls_err
dec ldec_xxx
select column_xxx into :ldec_xxx from TABLE_yyy where id=keyvalue; //如果有必要查询当前值的话.
if sqlca.sqlcode <0 then
ls_err=sqlca.sqlerrtext //先读错误信息,然后立即ROLLBACK再提示,以免提示时用户不确定,表还在锁定中
rollback; //立即回滚,以免其它用户等待.
messagebox("提示","数据库发生以下错误:~n"+ls_err)
return
end if

update column_xxx=:ldec_new from table_yyy where id=keyvalue; //有必要的话再加 and column_xxx = :ldec_xxx

if sqlca.sqlcode <0 then
ls_err=sqlca.sqlerrtext //先读错误信息,然后立即ROLLBACK再提示,以免提示时用户不确定,表还在锁定中
rollback; //立即回滚,以免其它用户等待.
messagebox("提示","更新数据时发生以下错误:~n"+ls_err)
return
end if

commit using sqlca;

这样就可以了,你在更新时,事务会锁定其它的操作.


最严格的并发控制:
Key and Updateable Columns + Use Update
对主键和所有可更新列进行检查:有任何一个列在提交时发生了变化即告失败,即阻止事物之间修改同一数据。
直接更新方式:阻止事物内部对主键列进行任何交叉修改(逻辑正确也不行)。

最宽松的并发控制:
Key Columns + Use Delete then Insert

yyoinge 2012-03-21
  • 打赏
  • 举报
回复
你需要打开数据窗口,在ROWS → Update Properties...中设置更新的相关属性
yyoinge 2012-03-21
  • 打赏
  • 举报
回复
你在dw的sqlpreview事件中,写
if sqltype <> previewselect! then messagebox('', sqlsyntax) 看看

1,108

社区成员

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

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