zoukankan      html  css  js  c++  java
  • [转载红鱼儿]kbmmw 开发点滴:kbmMW客户端提交事务的现场处理

    多层应用中的事务处理,是必须的,如果处理不好,就会出现各种数据不同步的现象,无法投入使用。以前用ASTA实现的多层应用,是在客户端利用ASTA机 制,将要提交的数据集、执行的SQL及SP,统统生成到一个脚本中,在ASTA是TAstaParamList,然后一次性提交到服务器,在服务器端在执 行这个脚本时,开启事务,执行脚本,如果成功则Commit,失败则Rollback。

    kbmMW提供了更好的事务处理机制,即可以在服务器端做事务处理(TkbmMWTransactionResolve)也可以在客户端处理(TkbmMWClientTransactionResolve)。

    在客户端,只要利用kbmMWClientTransactionResolve.Resolve(Query1,Query2,...)即可实现事务控制,此方法返回True,表明事务提交成功。如果提交失败,服务器端自动Rollback,完成事务回滚。

    有几个事件可以捕获提交失败信息。

    1.kbmMWClientQuery.OnResolveError事件

    2.kbmMWClientTransactionResolve.onResolveError事件

    此外,当kbmMWClientQuery在kbmMWClientTransactionResolve提时失败时,kbmMWClientTransactionResolve会为kbmMWClientQuery生成具体的错误记录的信息,保存在kbmMWClientQuery属性中,该属性是kbmMWMemTable类型。

    利用这几种方式,可以很好的处理事务失败后的错误提示等进一步处理。

    问题是当提交失账时,会产生新的问题:

    1.假设有T1,T2两个物理表,需要用户同时修改并提交

    2.当用户对T1,T2都做了修改后,用kbmMWClientTransactionResolve.Resolve(T1,T2)提交给服务器,当t2提交失败时,比如主键重复,问题就来了。

    3.如果用户修改了T2的主键重复错误,再次提交,这时,不会再产生提交错误。

    4.重新打开T1,T2,会发现T1的修改丢失,而T2正常修改了。

    这种情况,对用户的操作过程来讲,是大问题,明明改了业务数据,保存时产生错误,按错误提示修正了错误数据,再保存,系统保存成功,再次调出这笔业务数据,用户会发现,修改结果没有被正确的保存!

    对开发者来说,就是要在事务提交失败后,能恢复失败前的现场,即要把T1,T2的Delta保存起来,不能因为提交失败,而毁掉T1,T2的修改!

    试图查找kbmMW提供现成的机制(其实,感觉不应该发生这样的问题),没有找到。于是想一个方法,就是Resolve前将T1,T2保存起来,提交有错误再恢复。

    用AllData方法不行

    代码:

    在BeforeResolve事件保存

    procedure TForm2.kbmMWClientTransactionResolver1BeforeResolve(Sender: TObject;
      const ADatasets: TkbmMWClientCursorArray);
    begin
      v1:=kbmMWClientQuery1.AllData;
      v2:=kbmMWClientQuery2.AllData;

    end;

    //提交不成功,试图恢复(这里只是测试,正常应恢复没有出错的Query,好能再一次提交)

    procedure TForm2.Button2Click(Sender: TObject);
    begin
      if not kbmMWClientTransactionResolver1.Resolve([kbmMWClientQuery1,kbmMWClientQuery2,kbmMWClientQuery3]) then begin
        kbmMWClientQuery1.AllData:=v1;//这句出错,提示非法的属性值
        kbmMWClientQuery2.AllData:=v2;
      end;
    end;

    还有一种方法,就是把delta写入流,提交失败再恢复,不知是否可行?先放一下。

    问题一定出在TkbmMWClientTransactionResolver.Resolve方法中,硬着头皮跟踪一下,咱这功力看大侠的套路,心惊胆颤,运气还不错,终于查到,问题出ProcessErrorTable方法中:

    procedure TkbmMWCustomPooledCursor.ProcessErrorTable

    在这个方法中,这里做了CheckPoint,把Delta干掉了!当提交的数据集没有返回ErrorTalbe时,系统认为这个数据集正确提交,所以做了CheckPoint。

         // Check if no errortable defined.
         if (FErrorTable.FieldCount=0) or (FErrorTable.RecordCount<=0) then
         begin
              CheckPoint;
              exit;
         end;

    原因找到了,一时间还想不出最好的修改方法来解决这个问题。试图找到一个属性来控制这种行为,也没有找到。等xalion来帮助了!kbmMW客户端提交事务的现场处理

    和xalion讨论该问题,也没有找到kbmMW已有的机制,对于上面提到的问题点,也可以确定。

    再进一步分析一下ClientTransactionResolve.Resolve方法的执行过程,大体上分三步:

    1.对提交的数据集,制作成Variant数组及Stream

    2.将1生成的内容一次性提交到服务器端并接收返回的结果

    3.利用返回结果对每一个提交的数据集进行ErrorTable处理,问题就出在这一步上。

    首先,kbmMW从返回的结果,生成每个数据集的ErrorTable内容,然后根据ErrorTable,调用ProcessErrorTable方 法,ProcessErrorTable方法有两个主要目的:如果无错,则调用CheckPoint,取消这次提前的修改内容,有错,不调用 CheckPoint,触发OnResolveError事件。

    对于一个数据集是否要Checkpoint,不应该取决于当前数据集是否有错,而应该由本次提要的结果来决定,就是说:当事务成功,则每一个数据集都应该做Checkpoint,事务不成功,则对于无错的数据集也不能Checkpoint!

    按此想法,对ClientTransactionResolve.Resolve做了修改,测试上面遇到的问题,可以正确保存用户的修改。

    修改方法是注册掉原ProcessErrorTable的调用,然后增加下面的代码,核心那行,我加黑了!


                  cnt:=0;
                  for i:=low(ADatasets) to high(ADatasets) do
                  begin
                       with ADatasets[i] do
                       begin
                            if not IsDataModified then continue;
                            v:=vResult[cnt];
                            inc(cnt);
                            if VarIsNull(v) then continue;
                            if VarArrayHighBound(v,1)>2 then
                               sFlags:=v[3]
                            else
                               sFlags:='';
                            NoCheckpointOnError:=(pos('NOCHECKPOINTONERROR',sFlags)>0);

                            DisableMasterDetail;
                            try
                               bm:=GetBookmark;
                               try
                                  //如果整体事务成功或者当前表有错误
                                  if Result or (ErrorTable.RecordCount>0) then
                                     ProcessErrorTable(TransactionOperation<>mwtoResolve,NoCheckpointOnError);

                               finally
                                  try
                                     GotoBookmark(bm);
                                  except
                                  end;
                                  FreeBookmark(bm);
                               end;
                            finally
                               EnableMasterDetail;
                            end;
                       end;
                  end;

  • 相关阅读:
    ruby 二进制转十进制 Integer("0b101") = 5
    开始菜单和我的文档的我的图片及我的音乐变成 my pictrues 正常图标了
    ruby watir 莫名其妙的错误
    Excel SaveAS是去掉提示框
    apache && jboss安装
    ruby require include的区别
    ruby控制鼠标
    This error is raised because the column 'type' is reserved for storing the class in case of inheritance
    用正则表达式限制文本框只能输入数字,小数点,英文字母,汉字等各类代码
    ASP.NET 如何动态修改 Header 属性如添加 Meta 标签 keywords description!
  • 原文地址:https://www.cnblogs.com/xalion/p/2711009.html
Copyright © 2011-2022 走看看