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;

  • 相关阅读:
    Mysql备份工具xtraback全量和增量测试
    Linux进程管理四大工具ps dstat top htop
    Linux Netcat 命令——网络工具中的瑞士军刀
    Linux 下载工具 aria2
    C语言宏基础总结
    使用浏览器做编辑器
    设计模式(1)
    OpenGL 编程(1)
    使用ffmpeg推流
    FFMPEG 解码和编码(编码mjpeg)
  • 原文地址:https://www.cnblogs.com/xalion/p/2711009.html
Copyright © 2011-2022 走看看