不知道在三层中大家可否碰到过这种问题:由于客户端是多窗口,所以可能多个ClientDataSet对应服务器端的同一个Provider,不知大家如何解决。我使用了无状态Provider,但是在设计期没办法提取数据字段定义。

解决方案 »

  1.   

    这个比较复杂,也涉及到一些技巧.
    最简单的方法,设计多个Provider,然后动态切换.
      

  2.   

    现有200个表,大部分都会在数个模块中使用,而即使同一模块也可以是多实例版本,所以同一数据表对应多个Provider会造成服务器端极大的资源浪费.示意图如下:
      

  3.   

    ------------------------------
             |   服务器端                   |         |
             |------------------------------|
             |    ---------      ---------  |
             |   |Provider1|    |Provider2| |
             |    ---|-----      ---|-----  |
             |       |              |       |
              -------|--------------|-------
           ----------|--------------|--------------------------------------------------------
          |          |       客户端 |                                                        |
          |----------|--------------|--------------------------------------------------------|
          |          |              |                                                        |
          |    ------|--------------|----------------                                        |
          |   |窗体一|实例1         \                |                                       |
          |   |------|---------------\---------------|                                       |
          |   |    --|-----------    -\------------  |                                       |
          |   |   |ClientDataSet1|  |ClientDataSet2| |                                       |
          |   |    --------------    --------------  |                                       |
          |   |                                      |                                       |
          |    --------------------------------------                                        |
          |                             --------------|-----------|-----------               |
          |                            |窗体一实例2   |           |           |              |
          |                            |--------------|-----------|-----------|              |
          |                            |    ----------|---    ----|---------  |              |
          |                            |   |ClientDataSet1|  |ClientDataSet2| |              |
          |                            |    --------------    --------------  |              |
          |                            |                                      |              |
          |                             --------------------------------------               |
           ----------------------------------------------------------------------------------
          
      

  4.   

    这个问题也一直困扰着我。
    我的一些信息:
    调试环境:ORACLE9I+DELPHI+其他平台
    操作方法:在ORACLE中测试语句,然后写配置表<用来存储需要的字段信息>,ClientDataSet1中使用,另用配置表的信息完成对字段信息的提供。ClientDataSet1使用的是离线数据。
    只有在OPEN/UPDATE的时候才有激活Provider1
      

  5.   

    楼上“只有在OPEN/UPDATE的时候才有激活Provider1”,可能ClientDataSet一次性把所有记录
    下载到了本地,这样会导致网络洪流,可能淹没服务器。
      

  6.   

    其实好的解决办法是使用无状态Provider,但是它需要每个表都有主键,要不然就需要
    用多字段定位,但主要是字段信息的提供.
      

  7.   

    1。多个ClientDataSet对应服务器端的同一个Provider 可能会出现问题!!
      

  8.   

    在服务端写代码实现Data(OleVariant)值返回给客户端,不直接用Provider会好些。当然更新操作也要在服务端写个方法进行更新。自我感觉效率还可以。就是要写多点代码。
      

  9.   

    我已现在使用无状态Provider解决了这个问题,但还是希望大家就此问题发表一下
    自己的意见。由于上次没有考虑到篇幅宽度,所以使问题描述图发送后乱码,重排
    后如下:
     ----------------------------
    |        服务器端            |
    |----------------------------|
    |  ---------   ---------     |
    | |Provider1| |Provider2|    |
    |  ---|-----   ---|-----     |
     -----|-----------|----------
          |           |--------------------------------
          |-----------|---------------------------     |
     -----|-----------|-----------------------    |    |
    |     |   客户端  |                       |   |    |
    |-----|-----------|-----------------------|   |    |
    |     |           |                       |   |    |
    |  ---|-----------|------------------     |   |    |
    | |   |窗体一实例1 \                 |    |   |    |
    | |---|-------------\----------------|    |   |    |
    | |  -|------------  \-------------- |    |   |    |
    | | |ClientDataSet1| |ClientDataSet2||    |   |    |
    | |  --------------   -------------- |    |   |    |
    | |                                  |    |   |    |
    |  ----------------------------------     |   |    |
    |                                         |   |    |
    |      -----------------------------------+---     |
    |     |            -----------------------+--------
    |  ---|-----------|------------------     |
    | |   |窗体一实例1 \                 |    |
    | |---|-------------\----------------|    |
    | |  -|------------  \-------------- |    |
    | | |ClientDataSet1| |ClientDataSet2||    |
    | |  --------------   -------------- |    |
    | |                                  |    |
    |  ----------------------------------     |
     -----------------------------------------
      

  10.   

    晕到,敢问这位仁兄是如何理解Borland的三层开发模式的?
      

  11.   

    我以前做的一个项目的经验:系统架构分三层:数据库服务器层->COM+中间件层->客户表现层;COM+中间层又分为:数据引擎层及业务逻辑层,其中数据引擎层专门处理一些数据的查询、提交等重复的数据库操作,业务逻辑层专门处理一些业务逻辑动作,如做月结啊,增加一张订单啊之类的;其中,客户表现层与业务逻辑层及业务逻辑层与数据引擎层的数据包的传送都用 TClientDataSet.Delat封装,这样可以减少数据流量,我也看到有些公司用的是 TADODataSet.Recordset封装的,效率也不错。这样做,架构、效率绝对是一流的,但客户层要写的代码可能要多点。
      

  12.   

    现在做的一个三层的,表也就几十个,我也用的是一TDataSetProvider对多的TClientDataSet,
    只要在程序里动态的实现TClientDataSet的连接与释放,应该没有什么问题。不过如果多次打开关闭数据集,会使程序速度太慢。
      

  13.   

    如果使用封状技术,客户端在设计期很难确定数据描述,换句话说就是很难进行界面定制,比如
    报表设计,中文字段名翻译.我现在使用了数据运行期无状态绑定,解决了设计期字段定义这个问题,
    同时由于Provider的无状态,可以使数据集共享,但客户端需要保留自己的状态.
      

  14.   

    封装一下ADOQuery,Provider,ClientDataSet作为一个类,并且每创建一个这个类的对象时给Provider的Name指定一个名.这个名可以是一个字符串+ProviderCount;ProviderCount是全局变量,可以放在数据模块中.
      

  15.   

    每创建一个对象,inc(ProviderCount)
      

  16.   

    200多个表,就有200多个Provider。我要晕死了
    i25ffz(Martin) 说得对。三层不能和两层的C/S结构那样设计
      

  17.   

    其实三层结构除了将商务逻辑与表现层分离之外,我觉得还有一点很重要的是比C/S结构的控制
    更为灵活, 比如资源的有效利用,提供良好的仲裁机制,再借助轻量级的数据访问机制:dbExpress
    使得三层比C/S的运行效率以及资源利用率都有飞跃.其实分离及对象化使得设计条理更为清晰,
    安全性更好,但很少人考虑到其中对象间的资源共享,客户间资源的共享,其实也就是缺乏一种
    Pooling机制.
      

  18.   

    目前我的应用程序服务器设计结构如下,大家给些建议. -------------              -----------
    | 数据访问机制|            |           |
    | --------   -+------------+-  无状态  |
    ||        | | | 业务对象A  | | 业务对象|
    ||        | | |            | | Pooling |
    ||        |  -+------------+-          |
    || 无状态 |   |            |           |
    ||数据访问|  -+------------+-          |
    ||组件集合| | | 业务对象B  | |         |
    ||        | | |            | |         |
    ||   |    |  -+------------+-          |
    | ---+----    |            |           |
    |    |       -+------------+-          |
    |    |      | | 业务对象C  | |         |
    |    |      | |            | |         |
    |    |       -+------------+-          |
    |    |        |            |           |
    |    |       -+------------+-          |
    |    |      | | 业务对象D  | |         |
    |    |      | |            | |         |
    |    |       -+------------+-          |
    | ---+------- |            |           |
    ||   公共    ||             -----------
    || 数据连接  ||
    | ----------- |
     -------------
      

  19.   

    我采用Delphi 6在Win 2000下开发基于COM+的三层系统,数据库服务器和应用服务器安装在同一台机器上,采用TSocketConnection连接,该系统的客户端每天都会死机,客户数5个以上大概1天发生1或2次,发生在客户端连接上后,网络中有掉包或客户机长时间没操作异外的断开,应用服务器上还显示客户机的IP地址,应用服务有时就会死掉.请问如何解决
      

  20.   

    晕,给大家一个方法看看!
    {-------------------------------------------------------------------------------
      过程名:    TMaterialServer.OpenData
      作者:      李文凯
      日期:      2004.12.06
      描述:     请修改
      实现方法: 请修改
      参数:      SQLFlag: Integer; const SQLWhere: WideString; var Data: OleVariant
      返回值:    无
    -------------------------------------------------------------------------------}
    function TMaterialServer.OpenData(SQLFlag: Integer;
      const SQLWhere: WideString; var Data: OleVariant;
      var strMSG: WideString): Integer;
    var
      strSQL: string;
      strLog:string;
    begin
      strLog:='OpenData(SQLFLAG='+inttostr(SQLFlag)+',SQLWHERE='+SQLWHERE+')';
      Result:=1;
      strSQL:=getSQLByID(SQLFlag);
      if strSQL='' then
      begin
        strMSG:='编号为['+IntToStr(SQLFlag)+']的SQL语句没有定义!与请系统管理员联系!';
        MainServer.AddInformat(FUserNO,FUserName,'读数据',strMSG,strLog,1);
        Exit;
      end;
      if Trim(SQLWhere)<>'' then  strSQL:=Format(strSQL,[SQLWhere]);
      try
        dataset.Close;
        dataset.EnableBCD:=False;
        dataset.CommandText:=strSQL;
        dataset.Open;
        Data:=DSPRead.Data;
        dataset.Close;
        Result:=0;
      except
        On E:Exception do
        begin
          strMSG:='获得数据失败,与请系统管理员联系!';
          MainServer.AddInformat(FUserNO,FUserName,'读数据','编号['+IntToStr(SQLFlag)+'] 读取出错'+E.Message,strLog,1);
        end;
      end;
       cds.ProviderName:='';
    end;
      

  21.   

    Connection: TADOConnection;
      dataset: TADODataSet;
      DSPRead: TDataSetProvider;
    我就用一个!
      

  22.   

    你的代码要求数据一次性读完,假如一次查询数据过万,会导致网络洪泄.再者如果要是一次性读完,
    TDataSetProvider本身就是一个无状态的,你的代码也只是增加了数据访问的安全性(过滤非法SQL
    调用),我的做法是改造TDataSetProvider和TCliettDataSet.
      

  23.   

    也就是说,在TCliettDataSet的PacketRecord=-1的情况下多个TCliettDataSet对应一个TDataSetProvider是没有问题的,Borland的相关文档资料也提出在这种情况下TDataSetProvider
    是无状态的.
      

  24.   

    function OpenDataPage(ASQLID: Integer; const ASQLWhere: WideString;
          APage: Integer; var ATotalPage: Integer; var Data: OleVariant;
          var MSG: WideString): Integer; safecall;分页读取
      

  25.   

    你们的那种,根本无需改造TDataSetProvider和TCliettDataSet
    也是可以实现的!
      

  26.   

    我的业务逻辑使用了Pooling机制,同时共享了数据访问模块,所以数据访问模块必须无状态.
      

  27.   

    我一般是放多个Provider。还有动态创建Provider,用完了释放。
    服务器上是有访问就自己创建的,不明白,怎么会重复呢?顶一下。
      

  28.   

    lwk_hlj(阿凯(学习.net中)) 的架构模式跟我的很相似,有机会可以讨论一下。[email protected]
      

  29.   

    我有来了不知道在三层中大家可否碰到过这种问题:由于客户端是多窗口,所以可能多个ClientDataSet对应服务器端的同一个Provider,不知大家如何解决。我使用了无状态Provider,但是在设计期没办法提取数据字段定义。-----------------------------
    所以可能多个ClientDataSet对应服务器端的同一个Provider每个clientdataset在对数据操作的时候 
    在其BeforeApplyUpdates(Sender: TObject;
      var OwnerData: OleVariant);
    begin
       OwnerData:='select * form tablename';
    end;
      

  30.   

    其实这点Borland的更新机制本身已经是无状态了,唯一需要保护的是用户下载数据时需要用户记录自己的状态,这也是解决问题的关键,修改后的DataSetProvider和ClientDataSet具有了这种协调功能,所以每个DataSetProvider都可以重复利用,不会出现问题,所以中间件的数据访问模块利用率很高,再加上业务对象加入Pooling机制,经测试确实非常有效率。
      

  31.   

    问一下,DataSetProvider不是对每个客户端连接都建立新的进程么?
    惭愧得很,我现在有个项目的三层开发怎么跟大家讨论的都不太相同啊?大家把自己如何解决的也都说说啊,我们学习一下,呵呵
    另外加个问题:就是关于客户端与服务器端通信双方死机的问题,比如说在客户端调用中间应用服务器接口函数期间(返回之前),将服务器端的网线断了,客户端就死掉了,这些问题我找遍了资料都得不到答案,在版上问了多次,但也都没结果,不知道各位大哥在三层的实现中是不是从来都不存在这个问题阿?小弟很郁闷,呵呵
      

  32.   

    我觉得用主从数据模块解决这个问题比较好.
    请参考代码:
    Program Files\Borland\Delphi7\Demos\Midas\SharedConn