远程数据缓冲池

 

概述:独特的数据持久化方案:异构数据缓冲池

 

    异构数据缓冲池(DataPool) 中的核心对象DataStore提供了远程数据透明访问和操控的能力,使得客户端具有强大且安全的数据访问能力。

   DataStore 提供的功能有:

    它与DataBook(ZExcel)组件的结合提供了超强的客户数据表现和操控能力。

 

创建DataStore对象

    DataStore对象是一个脱机数据缓冲区管理对象,与JDBC中的RecordSet不同的是,后者始终与数据库建立连接。而DataStore仅仅是在本地计算机内存中建立的一个数据缓冲区,并不需要实时地与数据库优质连接,这样有效地减少了网络流量,降低网络负担,提高了容错性,有利于大数据量的集中操作。

    如果不作特殊说明,下面的示例脚本运行环境都将是指“协同平台二次开发运行环境”,其中的示例代码,都将可以在脚本练习中进行测试运行。

    通常创建一个DataStore对象使用 newDataStore 函数:

1 基于Select语句的DataStore

var ds=newDataStore("","select * from t1");

其中第一个参数""表示的是数据库连接池名称,使用""表示使用本应用的数据库连接。第二个参数是一个在效的Select语句 。

2基于存储过程的DataStore

例如,创建一个如下的存储过程

create procedure p_userinfo @id int
as
 select id,name , showname
 from news_user
 where id=@id

使用如下语句创建DataStore:

var ds= newDataStore("","p_userinfo ?"); 其中的? 是参数的占位符

 

检索数据

    当创建DataStore对象后,可能使用retrieve 函数检索数据,DataStore对象提供了一组retrieve 函数进行数据检索。它们的原型如下:

 

访问数据

    当检索出数据后,数据就存放在本计算机的内存中,DataStore 负责管理这个缓冲区。系统提供了一组函数来访问这些数据:

()

函数 说明  示例
getRowCount 得到数据行数 var rc=ds.getRowCount();
getValue 得到指定行列的数据 var name=ds.getValue(0,"name"); //0表示第一行
var name=ds.getValue(0,0);
setValue 修改数据 ds.setValue(0,"name", "张三");
ds.setValue(0,0, "张三");

    通常在知道字段类型时,可以使用更明确的函数来进行数据访问,比如:

getInt , getString , getDouble , getDate 详细的函数参考请参看DataStore对象参考

 

数据的增删

    当检索出数据后,数据就存放在本计算机的内存中, 使用insertRow 来增加一行,使用deleteRow来删除某行。这里的增删操作都是针对数据缓冲区进行的,并不会实时的反映到数据库中。

插入行:


var ds= newDataStore("","select * from t1");
var row= ds.insertRow(0);

函数insertRow(row) 中的参数row,表示在第几行之前插入一行。当row=0时,表示在最前面插入一行,当row大于行数时,表示是最后面插入一行。

删除行:


var ds= newDataStore("","select * from t1");
ds.retrieve();
var rc=ds.getRowCount();
for(i=rc-1 ; i>=0; i--)
{
   ds.deleteRow(i);
}
rc=ds.getRowCount(); //此时rc应该==0

上面的示例是从t1表中检索出数据,并全部删除,注意是从后往前删除的,(为什么要这么处理,做为一个思考题留给您)

函数  deleteRow( row) 参数row 表示是需要将第几行删除。注意0表示第一行。


相关事件:

deleteRow 函数删除指定的行。在删除前先触发事件 deleteRowPermit , 该事件的返回值直接表示允许不允许deleteRow执行。当deleteRowPermit 返回False时,表示不允许删除行,这时DeleteRow 函数并不删除指定的行。当没有在事件deleteRowPermit中写代码,或者deleteRowPermit返回True时,表示允许删除指定的行,deleteRow 执行删除操作,之后再触发事件 afterDeleteRow。
    

 

数据的修改

  使用 setValue( row, col , value)来修改指定行列的数据,示例:

var ds= newDataStore("","select * from t1");
ds.retrieve(" id=1" );
if ( ds.getRowCount()==1) ds.setValue( 0,"name","张三");

修改值触发的事件

     使用setValue 来修改某行某列的值,当SetValueWithRiskMode为False 时,系统对将要设置的值进行合法性检测,以防止将不合法的数据填充到某行某列(比如将字符型的值填充给日期型的字段).如果开发者能够确保将设置的值的合法性,那么可以将 SetValueWithRiskMode 设置成True, 这样在大量数据赋值时,忽略数据合法性检测将提高性能.

???? 当 SetValueWithTrigger =True 时, 使用 Value (row,col ) 对某行某列赋值,先触发ItemChangeAccept事件,如果该事件返回False,表示不接受将要设置的值,那么设置值失败。如果ItemChangeAccept事件返回True,或者该事件没有被处理,表示接受将要设置的值,并将该值填入到( row, col) 指定的缓冲区中,然后触发ItemChanged 事件。

     当 SetValueWithTrigger =False时, 系统直接将值填入到( row, col) 指定的缓冲区中,不触发任何事件。

     大量数据赋值时,将SetValueWithTrigger 设置成False时,不触发任何事件将大大提高系统性能。

 

修改值对计算列的影响

     当某个计算列引用某列的值,而该列的值发生改变时,系统将重新计算计算列的值,并触发计算列发生改变事件ComputerChanged。

     将要设置的新值与旧值相等时, setValue( row, col ,value) 不作任何处理,也不触发任何事件.

修改值对单元格状态和行状态的影响

     修改某行某列的值将影响该单元格的状态和所在行的状态:

单元格的状态和行的状态对数据提交的影响

     当调用DataStore 的函数 update 将数据更新到数据库时, 单元格的状态和行的状态将起决定性的作用. 

 

 

 

数据保存的内部流程

    通过 update 函数可以保存数据修改。update 函数在保存的过程中还要触发 validate 事件允许用户对数据的合法性进行校验,详细的流程如下:

 

单元格和行的状态对保存的影响

    DataStore 管理的是本地计算机内存中的数据缓冲区,检索数据的过程是将数据从数据库中取出来放到缓冲区中,保存的过程是将缓冲区中的修改提交到数据库中。所有的这些动作都完全依赖于DataStore中的每一个数据单元的状态以及数据行的状态。

ataStore对数据的管理实际上就是对数据状态的管理,并将数据的状态翻译成相应的SQL语句来实现数据库的操作。

   DataStore 管理着三个缓冲区:

    主缓冲区用来存放有效数据。过滤缓冲区用来存放从主缓冲区中过滤出来的数据。删除缓冲区用来存放主缓冲区中被删除的数据。当调用DataStore 的函数Update 做保存操作时,DataStore对象将主缓冲区中新增加的数据翻译成 Insert 语句,将被修改的数据翻译成 Update 语句,将删除缓冲区中的数据翻译成 Delete 语句。

    每一个数据单元格存放着两份数据,一份是从数据库检索出来的数据,另一份是单元格当前的数据(如果没有被修改,因该等于从数据库中检索出来的原始数据)。这两份数据以及数据单元格的状态决定Update 时的动作:

    所以,DataStore 的核心功能就是自动维护数据的状态,并将根据数据的状态解释成不通的SQL 语句作用于数据库从而实现数据管理的功能。

 

 

保存对单元格以及行的状态的影响

    使用 Update 函数保存数据。该函数具有一个参数用来设置是否在保存成功后是否将数据的状态复位。当 Update( True) 成功后,参数 True 表示将状态复位。对不同状态的行,复位状态后的结果是不同的:

 

    当执行Update(True) 成功后,再次执行 Update( True) 时不会执行任何实际的操作,因为数据没有发生变化。

    但是,但Update 的参数为False , 即执行 Update ( False) 后,所有数据的状态保持不变,之所以允许这样的处理,请参看 多表的同步更新。

 

 

多用户的并发更新控制

    当有多个用户同时修改相同的数据时, 如何进行控制呢??

    比如:000001号单据上的总金额为 500。这时,A,B两个操作员同时将该单据打开修改,A将总金额修改成 1000 , 并保存。B将总金额修改成2000 ,此时,在数据库中,该单据的总金额已经变成了 1000,而不是最初检索出来的 500 。那么,是否允许 B 操作员保存修改呢??

    DataStore 是通过 UpdateWhereClauseColumns 属性来控制多用户的并发更新。该属性定义了数据修改翻译成 Update 语句中的where 子句的结构。比如 UpdateWhereClauseColumns =" id | name | je " ,那么当用户修改了数据并调用Update 函数作保存时,被修改的数据被解释成 Update ????? Set col1= ??? , ... Where id=? and? name=? and je= ? 。 比如表 t1 中有列 id, name ,code, je? ,?? 检索出来某行数据为 id=1, name='wise', code='01', je=500 。A 、B 操作员同时将该数据检索出来修改。 A操作员将 je 修改成 1000 , 当A作保存时 , DataStore 将A所做的操作解释成 Update t1 set je=500 Where id=1 and name='wise' and je=500 。当A 保存成功后,数据库中该记录的je变成了1000 . 这时,B操作员将je 修改成 2000 , 当B作保存时 , DataStore 将B所做的操作解释成 Update t1 set je=2000 Where id=1 and name='wise' and je=500 。显然 B操作员的操作不会生效。因为数据库中已经不存在 id=1 并且 name='wise' 并且 je=500 的记录了。这样实现了策略二的要求。如果令 UpdateWhereClauseColumns= "id " 那么 B 操作员的操作被解释成 Update t1 set je=2000 Where id=1 。这时B的操作生效,实现策略一的要求。

    所以,出现在 UpdateWhereClauseColumns中的列越多,并发控制越严格。,出现在 UpdateWhereClauseColumns中的列越少,并发控制越宽松 。但表的主键必须出现在 UpdateWhereClauseColumns中。 比如表 t2 的主键是 name 和 code 组合而成,那么 name | code 必须出现在UpdateWhereClauseColumns中,否则无法正确更新数据。

    值得注意的是:DataStore 能够通过UpdateWhereClauseColumns来控制多用户同时多同一数据的更新,但对多用户对同一数据的删除不作控制,也就是说:如果A操作员删除了单据 000001 , 然后 B 操作员再删除单据 000001 , 虽然 B 操作员的删除操作没有删除任何数据(因为要删除的数据已经被删除),但系统仍然认为 B 操作员执行成功(因为他的目的的确已经达到)。

 

多表的整体更新

   

    有时需要将多个DataStore 的更新看做一个整体事务进行操作,比如一张发票包含有主要信息(包括单位名称,银行,帐号,地址等信息), 明细信息(包括货物,数量,单价,金额等)。保存了一张发票应该是主记录信息和明细记录信息同时保存,当任何一部分信息保存失败时,整个保存操作应该回滚撤销。

    DataStore 提供了事务功能支持。保存函数 Update 带有一个参数,表明在更新成功后是否复位数据的状态,结合数据库的事务处理和 DataStore 的数据状态管理,就可以实现多表的整体更新