任务(多线程并行)TFDMemTable内存表传参方式调用服务器返回的TDataSet

服务器端:

function TServerMethods1.getTFDDataSet
  ( const pSql,pSelectKey:string ):TDataSet;
  var iSql,iSelectKey:string;
  var FDQry1:TFDQuery;  FDCon1:TFDConnection;
      ACds:TClientDataSet;  TempProvider:TDataSetProvider;
      // FDMemTable:TFDMemTable;  //内存表处理也可
  var Msg:TJSONValue;  ifBroadcast:Boolean;
  var FieldDefsCount:Integer; AtestCount:Integer;
begin
    iSql:=pSql;  iSelectKey:=pSelectKey;
    //用内存表中转返回值回调的赋值时间:
    //FDMemTable:=TFDMemTable.Create(nil);

ACds:=TClientDataSet.Create(nil); //TClientDataSet
    if FDConGlobal.Connected=false then
      FDConGlobal.Connected:=true;

//    FDCon1:=TFDConnection.Create(nil); //FDCon此连接用完后不能释放只能断开交给连接管理员Pooling管理
//    FDCon1.ConnectionDefName:='MSSQL';

FDQry1:=TFDQuery.Create(FDConGlobal);   //FDQuery此连接用完后不能释放只能断开交给连接管理员Pooling管理
    FDQry1.Connection:=FDConGlobal;//:交给全局连接池,不要动态生成连接,否则客户端连续请求时,会提示Socket的IP和Address已经被占用啦

try
      FDQry1.FetchOptions.Mode:=fmAll;//FDQry1.FetchOptions.RecordCountMode:=cmTotal;//cmVisible
      FDQry1.FetchOptions.RecordCountMode:=cmFetched;
      FDQry1.FetchOptions.RowsetSize:=999999;
      FDQry1.FetchOptions.RecsMax:=-1;
      FDQry1.FetchOptions.RecsSkip:=-1;

//      FDMemTable.FetchOptions.Mode:=fmAll;//FDMemTable.FetchOptions.RecordCountMode:=cmTotal; //cmVisible
//      FDMemTable.FetchOptions.RecordCountMode:=cmFetched;
//      FDMemTable.FetchOptions.RowsetSize:=999999;
//      FDMemTable.FetchOptions.RecsMax:=-1;
//      FDMemTable.FetchOptions.RecsSkip:=-1;
    FDQry1.close;  FDQry1.DisableControls;
    FDQry1.SQL.Text:=iSql; FDQry1.EnableControls; //' select module_name,Report_name,com_id from ctl04000 ';
    FDQry1.Active:=true;//FDQry1.Open(iSql);
    FDQry1.First;

while FDQry1.State=dsInactive do sleep(0);
    if FDQry1.Active=true then FDQry1.First;
    ACds.FieldDefs:=FDQry1.FieldDefs;
    //Memo1.Lines.Add('TClientDataSet字段数:'+IntToStr(ACds.FieldDefs.Count));
    TempProvider:=TDataSetProvider.Create(nil);
    TempProvider.DataSet:=FDQry1; //:TClientDataSet的数据提供者
    ACds.Data:=TempProvider.Data;

//    if FDMemTable.State<>dsInactive then FDMemTable.Close;//FDMemTable.Active:=false;
//    FDMemTable.AppendData(FDQry1);
//    MainServerForm.Memo_Errors.Lines.Add('记录数:'+IntToStr(FDMemTable.RecordCount));
//    for AtestCount := 0 to FDMemTable.FieldDefs.Count-1 do
//      MainServerForm.Memo_Errors.Lines.Add('字段数:'+FDMemTable.FieldDefs[AtestCount].Name);
//    Result:=FDMemTable;//:回调客户端请求

while ACds.State=dsInactive do sleep(0);
    if ACds.Active=true then ACds.First;

MainServerForm.Memo_Errors.Lines.Add('记录数:'+IntToStr(ACds.RecordCount));
    for AtestCount := 0 to ACds.FieldDefs.Count-1 do
      MainServerForm.Memo_Errors.Lines.Add('字段数:'+ACds.FieldDefs[AtestCount].Name);
    Result:=ACds;

finally
    //ACds: TClientDataSet和TFDMemTable本质一样,都是内存缓存的,不需要释放,函数调用完毕后会自动释放,
      //若释放啦,因为返回需要时间,返回值会出问题
    try
      //if ( (testTFDDataSet_ifFinished.Trim).Indexof('OK')>=0 ) then
        //:上面的跟踪判断会滞后,要等响应完之后,不要用
      FDQry1.Active:=false; while FDQry1.State<>dsInactive do sleep(0);
      FreeAndNil(FDQry1);

FreeAndNil(TempProvider);//:TClientDataSet的数据提供者
      MainServerForm.Memo_Errors.Lines.Add('组件FDQry1释放成功!');
        //FDCon1.Close; //:【数据库连接取完数后】可以断开连接,连接不要释放,交给连接池自动管理。
        //:跟DSServerClass1.LifeCycle生命周期管理有关!【用完后】才能释放:需要下面搞清楚什么是【用完后】
    except
      MainServerForm.Memo_Errors.Lines.Add('释放出错啦');
    end;
  end;
end;

客户端:

1、公用代码单元(传入TFDMemTable内存表参数调用服务端):

function getFDMemT_SrvMethGetTFDDataSet(
  pSql: string; pSelectKey: string;
  var paramFDMemTable: TFDMemTable):Boolean;
var AFDMemTable:TFDMemTable;
  ATDataSet:TDataSet; FieldDefsCircle:Integer;
begin
  AFDMemTable:=TFDMemTable.Create(nil);  //:形参,产生和释放很重要
  AFDMemTable.FetchOptions.Mode:=fmAll;
  AFDMemTable.FetchOptions.RecordCountMode:=cmFetched;
  AFDMemTable.FetchOptions.RowsetSize:=9999999;
  AFDMemTable.FetchOptions.RecsMax:=-1;
  AFDMemTable.FetchOptions.RecsSkip:=-1;
  if AFDMemTable.State<>dsInactive then
  begin
    AFDMemTable.Close;
  end;
  try
    try
      //调用服务器上方法:
        //ATDataSet:直接赋值,既不要创建也不要释放:
      //if not Assigned(ATDataSet) then //多核多处理器环境,单核环境或win32应用不存在此问题!
        ATDataSet:=( ClientModule1.ServerMethods1Client.getTFDDataSet(pSql, pSelectKey) );
      while ATDataSet.State=dsInactive do sleep(0);  //:确认返回了数据
      if ATDataSet.Active=true then
      begin
        ATDataSet.First;

// 以下:形参 获取 从服务器返回的ATDataSet:TDataSet数据集数据
        AFDMemTable.FieldDefs.Clear;
        AFDMemTable.FieldDefs:=ATDataSet.FieldDefs;
        AFDMemTable.Open;
        while not (ATDataSet.Eof) do
        begin
          AFDMemTable.Append;
          for FieldDefsCircle := 0 to AFDMemTable.FieldDefs.Count-1 do
          begin
            AFDMemTable.FieldByName(AFDMemTable.FieldDefs[FieldDefsCircle].Name).Value:=ATDataSet.FieldByName(AFDMemTable.FieldDefs[FieldDefsCircle].Name).Value;
          end;
          AFDMemTable.Post;
          ATDataSet.Next;
        end;
        //Memo1.Lines.Add('TFDMemTable记录数:'+IntToStr(AFDMemTable.RecordCount));
        AFDMemTable.First;
        AFDMemTable.IndexesActive:=true;
        AFDMemTable.Active:=true;  //:形参 激活数据,以便下面传递给 实参
      end;
      paramFDMemTable.CloneCursor(AFDMemTable);    //:实参克隆形参的数据和游标
      //TMonitor.Exit(AFDMemTable);
    except
      //on E: TDSRestProtocolException do ClientModule1.HandleRestException(ClientModule1.DSRestConnection1, '客户端连接错误', E); else raise ;
      raise Exception.Create('客户端连接错误');
    end;
  finally
    if (AFDMemTable.Active=true)
    then Result:=true else Result:=false;
    AFDMemTable.Active:=false;    //:形参,施放前线关闭
    FreeAndNil(AFDMemTable);    //:形参,产生和释放很重要
  end;
end;

2、任务方式执行:内存表传参给公共单元获取数据

procedure TfmxMatter.btnListViewMain_SelectClick(Sender: TObject);
var ATask:ITask;  AEvent:TEvent;
    ADataSet: TDataSet;
begin
  FDMemTMain_Temp.FetchOptions.Mode:=fmAll;
  FDMemTMain_Temp.FetchOptions.RecordCountMode:=cmFetched;
  FDMemTMain_Temp.FetchOptions.RowsetSize:=9999999;
  FDMemTMain_Temp.FetchOptions.RecsMax:=-1;
  FDMemTMain_Temp.FetchOptions.RecsSkip:=-1;
  if FDMemTMain_Temp.State<>dsInactive then
  begin
    FDMemTMain_Temp.Close;//FDMemTMain_Temp.Active:=false;
  end;

btnListViewMain_EditSelected.Enabled:=false; //:按钮执行任务前加锁很重要
  Memo1.Lines.Clear;
  //多任务处理预留: if arrayTasks[0].Status=TTaskStatus.Running then arrayTasks[0].Wait(INFINITE);
    //ifFinishTask:=0;
  AEvent:=TEvent.Create; //:创建事件总线对象
  //创建并启动(多线程池化的)任务多核多处理器并行(多路CPU或GPU同时工作,或单处理器多核同步) //APool:= TThreadPool.Create; //:任务POSIX不能带池化参数产生
  ATask:=TTask.Create(
  procedure
    var AtestFieldDefsCircle:Integer;
  begin
    TMonitor.Enter(self,0); //多核多处理器环境,经常用uses system;  //:锁定监视器任务执行前进入锁监视状态:很重要
    try
      try
        try  // 调用上述公共单元,获取服务器返回的TDataSet数据 : 
          getFDMemT_SrvMethGetTFDDataSet(
            'select com_id,item_id,item_name,item_type, '
           +' convert(Datetime,convert(varchar(23),maintenance_datetime,121)) as maintenance_datetime '
           +' from ctl03001','物品资料',FDMemTMain_Temp);
          //while FDMemTMain_Temp.State=dsInactive do sleep(0);
        finally
          if FDMemTMain_Temp.Active=true then FDMemTMain_Temp.First;
          //Memo1.Lines.Add('TFDMemTable字段数:'+IntToStr(FDMemTMain_Temp.FieldDefs.Count));
          FDMemTMain_Temp.Open;

//Memo1.Lines.Add('TFDMemTable记录数:'+IntToStr(FDMemTMain_Temp.RecordCount));
          FDMemTMain_Temp.Last; FDMemTMain_Temp.First;//不像其基类TDataSet,TClientDataSet可以任意操纵Cursor,而且是双向的游标。
          FDMemTMain_Temp.IndexesActive:=true;

while not (FDMemTMain_Temp.Eof) do
          begin
            //此段代码只用于调试,POSIX不允许重复操作
              //:Doublication not Allowed:
            Memo1.Lines.Add(
              '索引字段数:'+IntToStr(FDMemTMain_Temp.IndexFieldCount)+','
             +'内存表索引记录数:'+IntToStr(FDMemTMain_Temp.IndexDefs.DataSet.RecordCount)+','
             +'内存表索引:'+IntToStr(FDMemTMain_Temp.IndexDefs.DataSet.RecNo-1)+','
             +'运营商编码:'+FDMemTMain_Temp.FieldByName('com_id').AsString.Trim+','
             +'物品编码:'+FDMemTMain_Temp.FieldByName('item_id').AsString.Trim+','
             +'物品名称:'+FDMemTMain_Temp.FieldByName('item_name').AsString.Trim+','
             +'型号:'+FDMemTMain_Temp.FieldByName('item_type').AsString.Trim+','
            );
            FDMemTMain_Temp.Next;
          end;
        end;
        //:上面是任务的具体内容!
        AEvent.SetEvent;//:事件总线通知:任务结束!
      except        // 万一异常,代码很重要 :
        TMonitor.Exit(self);
        btnListViewMain_EditSelected.Enabled:=true;
        AEvent.Free;//:出现异常释放:事件总线!
        exit;       //:出现异常就不要再往下执行了!
        raise Exception.Create('出错或取消啦');
      end;
    finally
      TMonitor.Exit(self);  //:锁定监视器适当时机解锁:很重要
      btnListViewMain_EditSelected.Enabled:=true;  //:按钮适当时机解锁很重要
      //AEvent.Free;
        //:切忌:将事件总线在try内释放AEvent.Free;
    end;
    //事件总线AEvent.SetEvent后:确认任务是否完成:
      //Assert(AEvent.WaitFor(15000)>TWaitResult.wrSignaled);
    //:调试时:确认任务结束时长的信息标记,即AEvent.SetEvent,然后:
    AEvent.Free; //:确认收到任务结束的信号标记即AEvent.SetEvent后再:释放事件总线对象
  end );
  //多任务管理://arrayTasks[0]:=ATask;//TTask.WaitForAll(arrayTasks); //if arrayTasks[0].Status=TTaskStatus.Running then arrayTasks[0].Wait(INFINITE);
  ATask.Start;

end;

任务(多线程并行)TFDMemTable内存表传参方式调用服务器返回的TDataSet相关推荐

  1. 【python教程入门学习】Python函数定义及传参方式详解(4种)

    这篇文章主要介绍了Python函数定义及传参方式详解(4种),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 一.函数初识 1.定 ...

  2. Spring Boot 传参方式

    2019独角兽企业重金招聘Python工程师标准>>> 最近在搞Spring Boot的项目,把传参方式总结一下.网上也参考一些文章,总结的很不错,这里借鉴一下. 注解 @Reque ...

  3. axios链接带参数_axios常见传参方式

    1:get请求 一般发送请求是这么写 axios.get('/user?id=12345&name=user') .then(function (res) { console.log(res) ...

  4. vue中路由传参方式之二(this.$router.push进行编程式路由跳转传参)

    this.$router.push进行编程式路由跳转传参 router中路由配置 组件home点击传参 组件homeDetails接受参数 router中路由配置 params第一种传参路由配置 {p ...

  5. http请求方式及传参方式

    http请求方式及传参方式 本文简单介绍一下http的几种请求方式以及集中传参方式的不同. 常见的几种请求方式 HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法. HTTP ...

  6. 【Postman】测试 Post 请求时传递数据失败 常见传参方式

    近期尝试使用 nod.js + vue 开发一个小项目. 第一次使用 postman 测试,遇到 POST 请求数据发送不过去的问题,做一个记录. JS 部分代码 //用户注册接口 router.po ...

  7. Android:页面跳转传参方式一,页面跳转传参方式二

     一.页面跳转传参方式一 跳转的过程如何传参:也就是页面之间如何传递参数,有点像函数调用如何传参,页面跳转也要传参. 复制一个工程 你要跳转,(现在的代码如下),intent 既然能设置跳转到哪个页面 ...

  8. mybatis传入数组怎么写_推荐的MyBatis传参方式List、数组等

    MyBatis 推荐的传参方式 如果要详细的学习 MyBatis,推荐看这个教程:https://www.w3cschool.cn/mybatis/ 1. 单个参数//接口方法int getAgeBy ...

  9. Python函数传参方式超级大汇总

    位置参数 位置参数传递是最为简单的传递方式,按照函数参数的位置顺序逐个匹配传入,传入参数的个数必须与函数参数个数一致. 见示例1,根据位置顺序进行匹配,a,b,c分别赋值为2,3,4 示例1 def ...

最新文章

  1. struts解决form提交的中文参数乱码问题
  2. 只导表前10条数据_【205期】面试官:数据量很大的情况下,对于分页查询你有什么优化方案吗?...
  3. 《2017中国大数据及AI人才发展报告》均薪38万,招聘猛增6倍
  4. fx5u mc协议_SLMP协议和MC协议
  5. 使用预先训练的SSD模型检测害虫
  6. Arduino编译bootloader
  7. 浅谈Borg/YARN/Mesos/Torca/Corona一类系统
  8. Java项目-食堂菜品点评系统(SpringBoot + SpringSecurity + Thymeleaf + Redis)
  9. UNIX 网络编程课程目录
  10. 园区内智慧出行标准化白皮书(2022年)
  11. 关于流程图的场景提炼,这一次终于说清楚业务流程图、功能流程图、页面流程图了
  12. 扇形涂色问题(Python)
  13. 上顿号符号_顿号在键盘上怎么打 常见的电脑符号输入方法说明
  14. 电子元器件简介——芯片封装篇
  15. Knockout JS 示例
  16. 代理对推广网站的四个作用
  17. C#字母与ASCII码的转换
  18. 10款不可多得的精美png图标
  19. 【UnityIUnity精灵Unity物体】生成控制大量物体的时间考究
  20. 跟牛老师一起学WEBGIS——WEBGIS实现(绘制切片)

热门文章

  1. 如何使用新版万能地图下载器下载谷歌地球影像
  2. linux命令进u 盘,UNetbootin Linux操作系统装进移动硬盘
  3. Springboot毕业设计毕设作品,图像AI风格转换系统 开题报告
  4. C#将服务器端excel文件下载到客户端的简单方法
  5. 网络编程(26)—— TIME_WAIT、FIN_WAIT1、FIN_WAIT2和CLOSE_WAIT状态的区别
  6. linux 更新字体
  7. Python+Vue计算机毕业设计电信营销派单系统4qv14(源码+程序+LW+部署)
  8. 美团动态线程池开源框架 DynamicTp
  9. python速成班1个月_Python速成班-基础篇DAY03
  10. 千万条记录,怎么做分页?怎么能提高性能?