zoukankan      html  css  js  c++  java
  • Delphi三层数据库开发应用

    服务器端程序实际上是个COM 工程,它本身连接数据源,再通过接口与
    客户端联系,这个COM 工程必须注册在服务器上。

       首先建立一个空白的工程。
       file -> New -> Other -> Multitier -> Remote Data Module(远程数据模块)
       对话框:
       Coclass Name : COM程序的名称,前台依据这个名字查找COM程序
                      (Project121)
       Instancing :执行模式,大部分用Multiple Instance(多重实例)
       Threading Model:线程模式,建议用Apartment(单元)  

       下面我们就会对这几个选择详加说明。

       OK,产生一个窗口,在这个窗口里,可以放入数据控件。

       在Viwe -> Type Libray 中,我们可以看到这个COM 的一些特性。我们
    也可以记下系统提供的GUID,以备后来使用。
       加入一个ADOTable,并设置其指向一个数据库。
       再设置一个DataSetProvider指向ADOTable

       这就完成了服务器端的程序设计。
       保存,编译,注册。

       这里需要做几个说明:
       1) 在客户端,数据控件一般要和Datasource相连,但在服务器端,主
    要要考虑数据和接口相连,Delphi 5.0以上版本规定,使用DataSetProvider
    就不需要再针对每个控件做Export(导出)操作,而是由应用程序服务器自
    动帮前台查找这就简化了程序和维护量。但是,前台每个DataSet 必须有个
    对应的DataSetProvider 才行。
       2)关于建立COM 是的几个选项现在说明一下:

       A) Instancing :
               Multiple Instance: 一个应用程序可以被多个前台程序调用使
                        用,启动和执行的效率比较高,不耗费服务器太多的
                        资源,管理上也比较方便。
               Single Instance: 一个应用程序只能被一个前台程序调用,由
                        于没有排队问题,所以当某个查询崩溃时,不会影响
                        其它的查询,但是,一个前台调用必然在服务器上建
                        立一个应用程序服务器的Process (进程),占用资
                        源比较多,影响服务器整体执行效率。
               Internal: 建立一个In-Process的COM 程序(也就是DLL文件
                        的格式),由于Mult-Tier 结构中,应用程序服务器
                        和前台程序是放在不同的地方的,两台机器的两个程
                        序就无法共享同一个Process,所以很少设置成Internal
                        模式的。
       B) Threading Model:
               Apartment: 每个实例一次只能处理一个前台发出的Request(请
                        求),如果同时建立多个In-Process COM 程序,那每
                        个COM 程序就会有一个现程服务,所以数据是安全的,
                        当然要注意某些共享变量的冲突。
               Single: 单线程,循环工作,不会出现多任务的问题。
               Free : 可以让Remote Data Module自己处理多线程问题,客
                        户端程序需要用多线程方法来处理。
               Both : 和Free几乎相同,但对应前台界面的Callback都是连
                        续的。

       如果注册后无法确认是否注册成功,可以用C:\WINNT\Regedit.exe检查。
      
        
       在Two-Tier模式中,客户端(Client)程序是直接和服务器的数据源相连的,
    而Multi-Tier模式,多个客户端连接的是一个应用程序服务器,因为收费是按
    客户端数计算的,所以,数据库的使用费用比较低。
       下面的例子只提供了数据库操作的最基本的功能,主要说明数据源的连接
    方法。

       1)建立一个普通的工程。    

       2)放置一个TDCOMConnrction控件(在Datasnap页),属性:
       ComputerName:服务器名(自动给出网上邻居)
       ServerName:应用程序服务器注册名(project121.Test121server)
       必要时ServerGUID输入GUID值。
       Connected=true 为激活

       说明:在调试的时候,如果是在Windows 2000本机的情况,可以先运行
    project121.exe,然后就可以在ServerName中找到project121.Test121server
    了,然后Connected=true 激活。

       3)放置一个TClientDataSet控件(在Data Access页),属性:
       Name:cdsCustomer(重新起名)
       RemoteServer: DCOMConnrction1
       ProviderName: DataSetProvider1(服务器端将被激活)
       Active:true (激活后将能正常连接)

       4)放置TDataSource,属性:
       Dataset:指向cdsCustomer。
       
       其余犹如普通的数据库设计。注意到这里使用了TActionList控件,其中
    写入和退出在Standard Action 内找不到,需要自己编写:

       procedure TForm1.ApplyUpdateExecute(Sender: TObject);
       begin
         cdsCustomer.ApplyUpdates(-1);
         ShowMessage('已经正确地写入数据库中!!');
       end;

       procedure TForm1.CloseActionExecute(Sender: TObject);
       begin
         Close;
       end;

       只要服务器端正确的注册,这个程序使用是没有问题的。

    第四节   客户端实现SQL 查询

       由于在客户端不存在TQuery控件,似乎客户服务器模式是无法做SQL
    查询的。但是,Delphi很好的解决了这个问题。事实上,只要客户端连接上
    服务端应用程序,客户端的TClientDataSet就包含了一个名字为Provider
    的属性,对应到服务器端DataSetProvider的所有默认属性和方法,其中
    DataSetProvider有一个Options属性,只要让其中的poAllowCommandText
    =true, 那么,DataSetProvider的poAllowCommandText就可以接受前台来
    的SQL 命令,并传送给TQuery。
       可以看出,真正传递数据的是DataSetProvider的接口,所以,用这个
    接口搭建传递SQL 的桥梁是必需的。
       客户端进行SQL 查询的方法是:

         ClientDataSet.Close;
         ClientDataSet.CommandText := 'SQL语句';
         ClientDataSet.Open;


          第五节   客户端查询服务器端的别名集

       在SQL 查询以前,用户往往需要制定查询哪个数据库,所以需要把服
    务器上BDE 数据库别名(Alias )设置数据抓到前台程序来
       具体做法是:

       首先,在服务器端建立一个TSession和一个TDataBase

       Session1属性:
       SessionName=Session1_4
       
       DataBase1属性:
       DataBaseName: 连接数据库名
       SessionName: Session1_4 (SessionName值)

       TQurey 增加个属性
       SessionName: Session1_4

       这样就可以用Session对象来管理数据源的信息了。
       为了传给客户端值
       
       View -> Type Library 显示接口窗口。
       右键 ITest125Server(具体根据设置名不同而不同) -> New ->
    建立两个方法:
       
       GetDatabaseNames ,用以传下别名数据,其接口信息为:
             Return type :HRESULT
             Parameters
       name         type          modifier

       Param        VARIANT*      [out,retval]

       SetDatabaseName , 用以接受客户机来的信息,其接口信息要求传入
    三个信息。

            Return type :HRESULT
             Parameters
       name         type          modifier

       DBName       BSTR          [in]      ----传上来的别名
       UserName     BSTR          [in]
       Password     BSTR          [in]

       刷新(Refresh Implementation)以后,就产生两个函数

    function TTest125Server.GetDatabaseNames: OleVariant;
    var
    I: Integer;
    DBNames: TStrings;
    begin
    // 建立一个字符串数组存放BDE所有的数据库别名数据。
    DBNames := TStringList.Create;
    try
       // 利用Session控件取得当前BDE所有的数据库别名数据。
       Session1.GetDatabaseNames(DBNames);

       /// 建立一个变量数组给函数返回变量Result。
       Result := VarArrayCreate([0, DBNames.Count - 1], varOleStr);

       // 最后再把数据库别名数据指定给该变量数组。
       for I := 0 to DBNames.Count - 1 do
         Result[I] := DBNames[I];
    finally
       DBNames.Free;
    end;
    end;

       上面的函数的关键除了取得BDE 数据库别名以外,还声明了一个变量数
    组来存放数据库别名数据,所以用VarArrayCreate函数建立一个变量数组,
    其中 参数1: 指定数组范围
         参数2: 数组数据类型,由于别名要通过DCOM传给前台,数据类型必
    须设成varOleStr 才有效。

       第二个过程是客户机提供上来的联机数据。

    procedure TTest125Server.SetDatabaseName(const DBName, UserName,
    Password: WideString);
    begin
    try
       // 把前台传来的数据库别名、用户上线名称、用户上线密码
       // 等三项数据指定给TDatabase控件,并且执行联机的操作。

       Database1.Close;
       Database1.AliasName := DBName;
       if (UserName<>'') and (Password<>'') then begin
         Database1.Params.Values['PASSWORD'] := Password;
         Database1.Params.Values['USER NAME'] := UserName;
       end;
       Database1.Open;
    except
         // 如果联机时发生错误,则产生一个exception给前台程序
       // 前台程序将会利用到这个exception来判断是否要把输入上
       // 线数据的窗口激活。

       on E: EDBEngineError do
    raise Exception.Create('Password Required') ;
    end;
    end;


    第六节   服务器端进行客户计数
       

       除了上面的功能外,这个程序还加上了一个在线用户以及查询用户统计
    的功能。由于这个应用程序执行模式是 Multiple Instance执行模式,所以
    当某个前台第一次连上线后,应用程序服务器会激活RemoteDataModule的
    事件程序,而断线后又会执行OnDestroy事件程序,因此就可以用这两个事件
    计算连上服务器的用户个数。至于Query个数的计算,则由TQuery的OnAfterOpen
    事件函数判断。

    -----------------------------------------------------------------
    Form1部分,主要用于显示
    -----------------------------------------------------------------

    procedure TMainForm.UpdateClientCount(Incr: Integer);
    begin
    FClientCount := FClientCount + Incr;
    ClientCount.Caption := IntToStr(FClientCount);
    end;

    procedure TMainForm.IncQueryCount;
    begin
    Inc(FQueryCount);
    QueryCount.Caption := IntToStr(FQueryCount);
    end;
    --------------------------------------------------------

    COM部分

    --------------------------------------------------------

    procedure TTest125Server.RemoteDataModuleCreate(Sender: TObject);
    begin
    // 增加一位前台上线者(调用Form1上的程序)
    MainForm.UpdateClientCount(1);
    end;

    procedure TTest125Server.RemoteDataModuleDestroy(Sender: TObject);
    begin
    // 减少一位前台上线者(调用Form1上的程序)
    MainForm.UpdateClientCount(-1);
    end;

    procedure TTest125Server.AdHocQueryAfterOpen(DataSet: TDataSet);
    begin
    // 新打开一个TQuery查询(调用Form1上的程序)
    MainForm.IncQueryCount;
    end;


       上述完整的客户/服务器数据库实例,见SQL服务器和SQL客户端两个程
    序,数据源部分需要自己调整。

    第七节   一对多表的服务器端程序

       一、Application Server

        事先要有一个标准的Form
       
        file -> New -> Multitier -> Remote Data Module

        CoClass Name :test63
        Instacting:   Multiple Instacting
        Threading Model: Apartment

        放入 ADOTable1
             ADOTable2
             Datasouce1
             DataSetProvider1(在Data Access)
             DataSetProvider2
        属性:
             ADOTable1(主表)
             ADOTable2(从表)
             用ConnectionString和TableName连上数据库
             

        ADOTable1                      DataSetProvider1

                   Datasouce1

        ADOTable2                      DataSetProvider2


       
        连上相应的数据库(这里为: 奖金数据库.mdb)
        TADOQuery.SQL=select * from 奖金
        TADOQuery.Active=true
       
        TDataSetProvider.Dataset=ADOQuery1

        保存(工程名改为pChpServer),运行(注册)


    客户端


    DCOMConnection1
    属性:ComputerName=计算机名(本地可以不写)
         ServerName=服务器端程序名(COM)
         Connecter=true (表示连上)


    ClientDataSet1  
       属性:RemoteServer=DCOMConnection1
             ProviderName=DataSetProvider1
             Active-=true
    ClientDataSet2  
       属性:RemoteServer=DCOMConnection2
             ProviderName=DataSetProvider2
             Active-=true

       加入两个TDataSource,TDBGrid分别连上
       ClientDataSet1和
       ClientDataSet2
       似乎应该显示主从关系了,但DBGrid2并没有显示。

       解决办法:
       双击ClientDataSet1,出现Form1.ClientDataSet1窗口,右键,快
    捷菜单上选Add Field 这时,我们可以看到最后一行出现:ADOTable2
    这是很重要的,正是靠这个建立了主从联接关系
       OK 让它进入Form1.ClientDataSet1窗口(也可以调整主表所显示
    的字段,但ADOTable2 不能少,它实际上是把从表作为主表的一个字段
    使用了)。
       ClientDataSet2属性:
       DataSetField=ClientDataSet1ADOTable2
       Active=true
       主从关系建立起来了。

  • 相关阅读:
    Understanding about Baire Category Theorem
    Isometric embedding of metric space
    Convergence theorems for measurable functions
    Mindmap for "Principles of boundary element methods"
    Various formulations of Maxwell equations
    Existence and uniqueness theorems for variational problems
    Kernels and image sets for an operator and its dual
    [loj6498]农民
    [luogu3781]切树游戏
    [atAGC051B]Three Coins
  • 原文地址:https://www.cnblogs.com/chenbg2001/p/1556401.html
Copyright © 2011-2022 走看看