中国计算机报1998年第53期  

PowerBuilder下实现多用户安全访问

张 锟

  PowerBuilder(以下简称PB)是一个非常优秀的数据库前端开发工具,在C/S结构中它处于客户端。在PB中,所有关于数据库方面的操作都交给DBMS完成,在一般情况下不用考虑多个用户同时访问数据库的问题。
  但DBMS提供的多用户支持仅仅限于SQL语句级,即保证两条SQL语句不会同时对一条记录进行操作。
  比如,有SQL语句A和B:
  A:Update target
   Set col1=col1+1
   Where keycol='key';
  B: Update target
   Set col1=col1+2
   Where keycol='key';
  其中,keycol是表target的关键字,col1是待修改的字段。
  显然,A语句和B语句都是可以再细分的操作,具体可以细分如下:
  A1: 查找keycol值为'key'的记录
  A2: 读取col1字段的值,并计算结果
  A3: 将结果写回数据库
  B1-B3同A1-A3一样,只是B2在具体计算上有所不同。
  如果DBMS无法保证A语句和B语句的互斥,就有可能发生写丢失。比如col1的值为2,如果执行次序为(A1,A2,A3,B1,B2,B3)或(B1,B2,B3,A1,A2,A3),即A、B语句互斥,结果应为5。但如果执行次序为(A1,A2,B1,B2,B3,A3),结果col1的值就成了3,B3进行的写操作就丢失了。所以DBMS在设计时,充分考虑了SQL语句级的并发性。
  但是,如果上面的A和B不是单条SQL语句,而是SQL语句序列,那DBMS就无法保证并发性的安全了。尤其是考虑到PB可以在脚本(Script)中混排SQL语句和PB语句,这种安全性就更加无法保障。
  比如语句序列C是由SQL语句和PB语句混排而成,同时有多个实例运行,让我们看一看在这种情况下,如何保证并发的安全性。为了方便起见,在例子中的PB语句是用伪语言写的。
  语句序列C 为:
  C1:select col1 into :value
   from target where keycol='key'; //将col1的值赋给变量value
  C2:chg=value>100 //chg为逻辑变量
  C3:if chg
   A //执行SQL语句A
   else
   B //执行SQL语句B
   end if
  其中,A、B指的是前面的SQL语句A和B。
  如果两台计算机上同时运行序列C,就有可能发生写丢失。因此,语句序列一级的并发安全性必须由程序来保证。
  上述问题如何解决呢?在写记录时,检查该记录是否被修改过,如果被修改过,就放弃写操作。
  以上面的语句序列C为例,只要在C1执行完毕后,将读到的记录值存下来,等到C3执行的时候,在A和B中加入相应的where条件,比较现在的记录值是否与原来一致,就能够判断出在C1和C3之间该记录是否被修改过。
  假设表target只有keycol和col1两列,那么只用修改A和B,就能将序列C改为具有并发安全性的序列。
  A和B的修改如下:
  A:Update target
   Set col1=col1+1
   Where keycol='key'
   And col1=:value;
  B: Update target
   Set col1=col1+2
   Where keycol='key'
   And col1=:value;
  其中,变量value是前面在C1运行的时候中记录下来的。
  如果表中还有其他序列,就要修改语句C1,将其他序列同时记录下来,并在A和B的条件中加入相应的判断条件。
  在使用这种办法的时候要注意,应该用一条Select语句来记录表中的记录值,而不要分散到多条语句中去。同样,在写记录时,应该在Update语句中加入判断条件,而不要先判断,再写入。否则,仍然会存在并发性问题。

 back.gif (1185 字节)