delphiXE DataSnap服务器供客户端调用的TDataModule类方法的本质与TFDJsonDatasets数据集列表的JSon序列化调用及内存泄漏原因和解决

delphiXE DataSnap服务器供客户端调用的TDataModule类方法的本质

与TFDJsonDatasets数据集列表的JSon序列化调用

及内存泄漏原因和解决

一、delphiXE DataSnap服务器供客户端调用的TDataModule类方法的本质

              //:因为方法返回TFDJsonDatasets对象是为远程客户端调用准备的:
                //:它的释放是在客户端代理TServerMethods1Client中进行的:unit ClientClassesUnit1;:
                  //:用Datasnap.DSProxyRest.TDSRestClient判断客户端进行实例化调用后
                  //:再用Datasnap.DSClientRest.TDSRestCommand在客户端进行释放FreeOnExecute的
                  //if FInstanceOwner then FGetAbigTFDJSONDataSetsCommand.FreeOnExecute(Result);


二、delphiXE DataSnap服务器供客户端调用的TDataModule类方法的调用

type
{$METHODINFO ON} //被它包裹,客户端才能访问
//TDataModule:  需要  {$METHODINFO ON} {$METHODINFO OFF}编译指令 让客户端 可以 呼叫

  TServerMethods1 = class(TDataModule)

  private
    { Private declarations }

    ///<summary>过程传入TFDJSONDataSets:服务端请求1个TFDJSONDataSets数据集列表:</summary>
    procedure ProduceAbigTFDJSONDataSets(
      const LFDJSONDataSets: TFDJSONDataSets;
      const DatasTab1Key, DatasTab1Sql,
      DatasTab2Key, DatasTab2Sql,
      DatasTab3Key, DatasTab3Sql: string);

  public

    ///<summary>方法返回TFDJSONDataSets:客户端请求1个TFDJSONDataSets数据集列表:</summary>
    function GetAbigTFDJSONDataSets(
      const DatasTab1Key,DatasTab1Sql,//:数据表对象1
      DatasTab2Key,DatasTab2Sql, //:数据表对象2
      DatasTab3Key,DatasTab3Sql:string  //:数据表对象3
    ): TFDJSONDataSets;


    ///<summary>2、客户端Rest请求数据库服务器顺序执行存储过程的方法getTablesStruct: </summary>
    ///<summary>2.1、sp_getTablesStruct:将系统表CtL00001中没有的从系统表视图VIEW_Database_Table中插入</summary>
    ///<summary>2.2、将系统数据字典表DataDictionary中没有的从系统表结构视图VIEW_Table_Struct中插入或修改</summary>
    ///<summary>:输入参数列表InputsList中应含com_id:</summary>
    ///<summary>:返回是否成功回调的TJSonObject格式的字符串string:</summary>
    function getTablesStruct:TJSonObject;

var
  ServerMethods1: TServerMethods1;

{$METHODINFO OFF} //:以上的模块:被METHODINFO ON包裹,客户端才能访问function!

//:::以上的是窗体函数:的调用单元
  //下面和implementation实现 之间放的的模块:与窗体无关:
  //var ... :变量
  //procedure ... :过程
  //function ...  :函数方法

implementation
{$R *.dfm}
 

三、TFDJsonDatasets数据集列表的服务端与客户端的调用与内存泄漏问题

3.1、看个案例:由TFDJsonDatasets返回的多个数据集列表,将其做TJSonObject序列化,返回给客户端

服务端:

function TServerMethods1.getTablesStruct:TJSonObject;
//:Rest请求数据库服务器执行用户表列表的表CtL00001及其表结构的表DataDictionary保持最新
var LJSonString:string;  //LEncoding:TEncoding;
var LFDJsonDatasets :TFDJsonDatasets;
  ifFinished:Boolean; LFDJSONInterceptor:TFDJSONInterceptor;
  LDatasTab1Key,LDatasTab1Sql:string;//:数据表对象1
  LDatasTab2Key,LDatasTab2Sql:string; //:数据表对象2
  LDatasTab3Key,LDatasTab3Sql:string;  //:数据表对象3
  UseBoolStrs: TUseBoolStrs;
begin
  //LEncoding:=TEncoding.GetEncoding('GB2312'); //LEncoding.GetString( //LEncoding.GetBytes( //UTF8String(LJSonString)
  //:执行特定的存储过程(内部不涉及com_id的处理)sp_getTablesStruct:
  LFDJsonDatasets := TFDJsonDatasets.Create;
  LFDJSONInterceptor:=TFDJSONInterceptor.Create;
  Result:=TJSonObject.Create;
  try
    LJSonString:=performStoreProc('sp_getTablesStruct','001',LJSonString);
    if LJSonString.Trim='处理表结构成功' then
    begin
      //TThread.Synchronize(nil,procedure begin
        //MainServerForm.Memo_Errors.Lines.Add('处理表结构成功'); end );
      try
          LDatasTab1Key:='CtL00001'; LDatasTab1Sql:='select * from CtL00001';//:数据表对象1
          LDatasTab2Key:='DataDictionary'; LDatasTab2Sql:='select * from DataDictionary'; //:数据表对象2
          LDatasTab3Key:=''; LDatasTab3Sql:='';  //:数据表对象3
          //此处用过程传参获取LFDJsonDatasets:
            //:切忌使用方法返回TFDJsonDatasets:
              //:否则返回时内存泄漏你永远释放不掉这个TFDJsonDatasets实例
               
//: function TServerMethods1.GetAbigTFDJSONDataSets: (内存泄漏):

                {  //  内存泄漏  :

                LFDJsonDatasets:=

                    GetAbigTFDJSONDataSets(
                      LDatasTab1Key,LDatasTab1Sql,
                      LDatasTab2Key,LDatasTab2Sql,
                      LDatasTab3Key,LDatasTab3Sql );    }

              //:因为方法返回TFDJsonDatasets对象是为远程客户端调用准备的:
                //:它的释放是在客户端代理TServerMethods1Client中进行的:unit ClientClassesUnit1;:
                  //:用Datasnap.DSProxyRest.TDSRestClient判断客户端进行实例化调用后
                  //:再用Datasnap.DSClientRest.TDSRestCommand在客户端进行释放FreeOnExecute的
                  //if FInstanceOwner then FGetAbigTFDJSONDataSetsCommand.FreeOnExecute(Result);

            ProduceAbigTFDJSONDataSets(LFDJsonDatasets,
              LDatasTab1Key,LDatasTab1Sql,
              LDatasTab2Key,LDatasTab2Sql,
              LDatasTab3Key,LDatasTab3Sql );   
//: procedure传参:TFDJsonDatasets

          ifFinished:=LFDJSONInterceptor.DataSetsToJSONObject(
            LFDJsonDatasets,
            Result );
          while ifFinished=false do sleep(0);
          if ifFinished=true then
          TThread.Synchronize(nil,procedure begin
            MainServerForm.Memo_Errors.Lines.Add('执行了获取数据集列表'); end );
      finally
        FreeAndNil(LFDJsonDatasets);
      end;
    end;
  finally
    LFDJSONInterceptor.Free;
  end;

end;

procedure TServerMethods1.ProduceAbigTFDJSONDataSets(
  const LFDJSONDataSets:TFDJSONDataSets;
  const DatasTab1Key,DatasTab1Sql,//:数据表对象1
  DatasTab2Key,DatasTab2Sql, //:数据表对象2
  DatasTab3Key,DatasTab3Sql:string  //:数据表对象3
);
var dispLog:string; LFDQuery1,LFDQuery2,LFDQuery3:TFDQuery;
  LFDJsonWrit:TFDJsonDatasetsWriter;
begin
  //Encoding := TEncoding.GetEncoding('GB2312');//:无需:TFDJsonDatasets已经Encoding啦

  LFDQuery1:=TFDQuery.Create(FDConGlobal);    //:FDConGlobal:池化的连接
  LFDQuery1.Connection:=FDConGlobal;
  LFDQuery1.FetchOptions.Mode:=fmAll;
  LFDQuery1.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery1.FetchOptions.RowsetSize:=9999999;
  LFDQuery1.FetchOptions.RecsMax:=-1;
  LFDQuery1.FetchOptions.RecsSkip:=-1;

  LFDQuery2:=TFDQuery.Create(FDConGlobal);
  LFDQuery2.Connection:=FDConGlobal;
  LFDQuery2.FetchOptions.Mode:=fmAll;
  LFDQuery2.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery2.FetchOptions.RowsetSize:=9999999;
  LFDQuery2.FetchOptions.RecsMax:=-1;
  LFDQuery2.FetchOptions.RecsSkip:=-1;

  LFDQuery3:=TFDQuery.Create(FDConGlobal);
  LFDQuery3.Connection:=FDConGlobal;
  LFDQuery3.FetchOptions.Mode:=fmAll;
  LFDQuery3.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery3.FetchOptions.RowsetSize:=9999999;
  LFDQuery3.FetchOptions.RecsMax:=-1;
  LFDQuery3.FetchOptions.RecsSkip:=-1;
  try
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin //数据表对象1
        dispLog:=DatasTab1Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab1Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        LFDQuery1.DisableControls;
        LFDQuery1.SQL.Text :=dispLog;
        LFDQuery1.EnableControls;
        LFDQuery1.Active :=True;//LFDQuery1.Open;//:都可以
        while LFDQuery1.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 主表记录数:'+IntToStr(LFDQuery1.RecordCount) );
        //MainServerForm.Memo_Errors.Lines.Add('-- 测试主表记录字段值:'+LFDQuery1.FieldByName(LFDQuery1.FieldDefs[3].name).AsString.Trim );
      end;
    finally
    end;
    try
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin //数据表对象2:
        dispLog:=DatasTab2Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab2Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        LFDQuery2.DisableControls;
        LFDQuery2.SQL.Text :=dispLog;
        LFDQuery2.EnableControls;
        LFDQuery2.Active :=True;
        while LFDQuery2.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 从表记录数:'+IntToStr(LFDQuery2.RecordCount) );
      end ;
    finally
    end;
    try
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin //数据表对象3:
        dispLog :=DatasTab3Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab3Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        LFDQuery3.DisableControls;
        LFDQuery3.SQL.Text :=dispLog;
        LFDQuery3.EnableControls;
        LFDQuery3.Active :=True;
        while LFDQuery3.State=dsInactive do sleep(0);
      end ;
    finally
    end;
    LFDJsonWrit:=TFDJsonDatasetsWriter.Create(LFDJsonDatasets);
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        while LFDQuery1.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab1Key,LFDQuery1 );
      end;
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        while LFDQuery2.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab2Key,LFDQuery2 );
      end;
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        while LFDQuery3.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( LFDJSONDataSets, DatasTab3Key,LFDQuery3 );
      end;
    finally
    end;

  finally
    FreeAndNil(LFDJsonWrit);
    //释放它们就是在释放数据库连接:交给池//:LFDQuery1.Free;  LFDQuery2.Free;  LFDQuery3.Free;

  end;
end;
 

function TServerMethods1.GetAbigTFDJSONDataSets(
  const DatasTab1Key,DatasTab1Sql,//:数据表对象1
  DatasTab2Key,DatasTab2Sql, //:数据表对象2
  DatasTab3Key,DatasTab3Sql:string  //:数据表对象3
): TFDJSONDataSets;
//:服务端调用会内存泄漏,客户端调用会执行完后自动释放:
var dispLog:string; LFDQuery1,LFDQuery2,LFDQuery3:TFDQuery;
  LFDJSONDataSets:TFDJSONDataSets;
  LFDJsonWrit:TFDJsonDatasetsWriter;
begin
  //Encoding := TEncoding.GetEncoding('GB2312');//:无需:TFDJsonDatasets已经Encoding啦
  //LFDJSONDataSets := TFDJsonDatasets.Create;
  Result := TFDJsonDatasets.Create;

  LFDQuery1:=TFDQuery.Create(FDConGlobal);   //:FDConGlobal:池化的连接
  LFDQuery1.Connection:=FDConGlobal;
  LFDQuery1.FetchOptions.Mode:=fmAll;
  LFDQuery1.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery1.FetchOptions.RowsetSize:=9999999;
  LFDQuery1.FetchOptions.RecsMax:=-1;
  LFDQuery1.FetchOptions.RecsSkip:=-1;

  LFDQuery2:=TFDQuery.Create(FDConGlobal);
  LFDQuery2.Connection:=FDConGlobal;
  LFDQuery2.FetchOptions.Mode:=fmAll;
  LFDQuery2.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery2.FetchOptions.RowsetSize:=9999999;
  LFDQuery2.FetchOptions.RecsMax:=-1;
  LFDQuery2.FetchOptions.RecsSkip:=-1;

  LFDQuery3:=TFDQuery.Create(FDConGlobal);
  LFDQuery3.Connection:=FDConGlobal;
  LFDQuery3.FetchOptions.Mode:=fmAll;
  LFDQuery3.FetchOptions.RecordCountMode:=cmVisible;
  LFDQuery3.FetchOptions.RowsetSize:=9999999;
  LFDQuery3.FetchOptions.RecsMax:=-1;
  LFDQuery3.FetchOptions.RecsSkip:=-1;
  try
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin //数据表对象1
        dispLog:=DatasTab1Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab1Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        LFDQuery1.DisableControls;
        LFDQuery1.SQL.Text :=dispLog;
        LFDQuery1.EnableControls;
        LFDQuery1.Active :=True;//LFDQuery1.Open;//:都可以
        while LFDQuery1.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 主表记录数:'+IntToStr(LFDQuery1.RecordCount) );
        //MainServerForm.Memo_Errors.Lines.Add('-- 测试主表记录字段值:'+LFDQuery1.FieldByName(LFDQuery1.FieldDefs[3].name).AsString.Trim );
      end;
    finally
    end;
    try
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin //数据表对象2:
        dispLog:=DatasTab2Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab2Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        LFDQuery2.DisableControls;
        LFDQuery2.SQL.Text :=dispLog;
        LFDQuery2.EnableControls;
        LFDQuery2.Active :=True;
        while LFDQuery2.State=dsInactive do sleep(0);
        MainServerForm.Memo_Errors.Lines.Add('-- 从表记录数:'+IntToStr(LFDQuery2.RecordCount) );
      end ;
    finally
    end;
    try
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin //数据表对象3:
        dispLog :=DatasTab3Sql;
        MainServerForm.Memo_Errors.Lines.Add('-- 生成的'+DatasTab3Key+'的sql:'+#13+#10+ dispLog );
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        LFDQuery3.DisableControls;
        LFDQuery3.SQL.Text :=dispLog;
        LFDQuery3.EnableControls;
        LFDQuery3.Active :=True;
        while LFDQuery3.State=dsInactive do sleep(0);
      end ;
    finally
    end;
    LFDJsonWrit:=TFDJsonDatasetsWriter.Create(Result);
    try
      if (DatasTab1Key.Trim<>'') and (DatasTab1Sql.Trim<>'') then
      begin
        if LFDQuery1.Active =True then LFDQuery1.Active :=False;
        while LFDQuery1.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( Result, DatasTab1Key,LFDQuery1 );
      end;
      if (DatasTab2Key.Trim<>'') and (DatasTab2Sql.Trim<>'') then
      begin
        if LFDQuery2.Active =True then LFDQuery2.Active :=False;
        while LFDQuery2.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( Result, DatasTab2Key,LFDQuery2 );
      end;
      if (DatasTab3Key.Trim<>'') and (DatasTab3Sql.Trim<>'') then
      begin
        if LFDQuery3.Active =True then LFDQuery3.Active :=False;
        while LFDQuery3.State<>dsInactive do sleep(0);
          LFDJsonWrit.ListAdd( Result, DatasTab3Key,LFDQuery3 );
      end;
    finally
    end;

  finally
    FreeAndNil(LFDJsonWrit);
    //释放它们就是在释放数据库连接:交给池//:LFDQuery1.Free;  LFDQuery2.Free;  LFDQuery3.Free;
  end;

end;

发布了61 篇原创文章 · 获赞 6 · 访问量 5579

猜你喜欢

转载自blog.csdn.net/pulledup/article/details/102370065