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;