首页 > 代码库 > [DIOCP3/MyBean/QDAC开源项目] DataModule-DB例子基于MyBean的插件实例<三层数据库方案>

[DIOCP3/MyBean/QDAC开源项目] DataModule-DB例子基于MyBean的插件实例<三层数据库方案>

【说明】

这个例子答应大家很久了,一直没有时间弄,现在正式结合MyBean插件可以很方便的在客户端共享操作连接,执行数据库的各项工作,屏蔽了底层的通信解码器编码等工作,直接传递Variant,给了开发者足够的领活和自由。

 

【服务端使用技术】

diocp3:担当底层的通信任务。

qworker/iocpTask:担当业务逻辑的处理工作,diocp3接受数据解码后用qworker/iocpTask将数据包投递出来,这样不用占用通信线程。

qmsgpack:负责将传递的将variant数据打包到流,从流中解码成variant

dataModule:对应连接的对象,方便进行开发。

 

【客户端】

myBean:制作基于MyBean框架的插件,可以在MyBean的框架模块中直接使用。

RawTcpClient:用于和服务端进行通信,阻塞的tcp客户端,类似IdTcpClient的精简版本,操作容易。

 

【DEMO使用】

说 明:客户端依赖diocp_bean.dll插件与服务器进行数据交换,DIOCP_DBDEMO.dll是演示窗体插件的宿主。

存放路径:MyBean\samples\diocp-DBDEMO

启动服务:SERVER_EXE\diocp3Server.exe  <点击start按钮启动服务>

image

服务器是基于DIOCP3的。可以在DIOCP3项目中找到源码[diocp3\samples\socket-Coder\DataModuleDEMO]

启动客户端:打开 [simpleConsole.exe], 依次点击下面的按钮就可以看到效果了

image

 

【DEMO说明】

服务端处理:

    服务端基于DIOCP3通信,该DEMO做了简单的封装,使用户可以专注于逻辑的实现,和客户端交互使用variant类型进行。

dmMain,是和客户端连接想对应的一个对象[和客户端的连接是一对一的关系]。

image

 

我在里面稍微做了下逻辑处理的演示:

function TdmMain.Execute(pvCmdIndex: Integer; var vData: OleVariant): Boolean;begin  case pvCmdIndex of    0:      begin        // 返回服务端时间给客户端        vData := Now();        Result := true;      end;    1:  // 查询数据      begin        // vData 认为是传入的SQL语句        //   执行后, vData为查询的数据,可以用于对ClientData.Data的赋值        qryMain.Close;        qryMain.SQL.Clear;        qryMain.SQL.Add(vData);        qryMain.Open;        vData := dspMain.Data;        Result := true;        qryMain.Close;      end;    2:      begin        // vData 为执行的语句        conMain.BeginTrans;        try          qryMain.Close;          qryMain.SQL.Clear;          qryMain.SQL.Add(vData);          qryMain.ExecSQL;          conMain.CommitTrans;          VarClear(vData);                    Result := true;        except          conMain.RollbackTrans;          raise;        end;      end;  end;end;

   vData,是客户端传递过来的参数,也是返回给客户端的数据。vData是OleVariant可以容纳任何的数据<配合qmsgPack可以达到任何的数据格式要求>, 如果还达不到你的格式要求,你可以在MyClientContext的dataReceived函数做些修改,下面代码的处理过程依次是:

解压收到的数据->QmsgPack解包->取出客户端传入的参数->调用dmMain.Execute处理逻辑->qmsgPack编码数据->压缩数据->回传数据到客户端

procedure TMyClientContext.dataReceived(const pvDataObject: TObject);var  lvMsgPack:TQMsgPack;  lvStream :TStream;  lvStream2:TMemoryStream;  vData:OleVariant;  lvResult:Boolean;begin  lvMsgPack := TQMsgPack.Create;  try    try      if FdmMain = nil then FdmMain := TdmMain.Create(nil);      lvStream := TStream(pvDataObject);      lvStream.Position := 0;      // upZip      TZipTools.unCompressStreamEX(lvStream);      lvStream.Position := 0;            // unpack      lvMsgPack.LoadFromStream(lvStream);      // get param      vData := lvMsgPack.ForcePath(cmd.data).AsVariant;      // invoke dataModule function      lvResult := FdmMain.Execute(lvMsgPack.ForcePath(cmd.index).AsInteger, vData);      // write result info      lvMsgPack.Clear;      lvMsgPack.ForcePath(__result.result).AsBoolean := lvResult;      lvMsgPack.ForcePath(__result.data).AsVariant := vData;    except      on E:Exception do      begin        lvMsgPack.Clear;        lvMsgPack.ForcePath(__result.result).AsBoolean := false;        lvMsgPack.ForcePath(__result.msg).AsString := e.Message;      end;    end;    lvStream.Size := 0;    lvMsgPack.SaveToStream(lvStream);    lvStream.Position := 0;    // zipStream    TZipTools.compressStreamEX(lvStream);    lvStream.Position := 0;    // send to client    self.writeObject(lvStream);  finally    lvMsgPack.Free;  end;end;

 

客户端处理:

   编译的 DLL 放到和EXE同一个目录下面就可以进行自动加载。

   客户端diocp_bean工程中

library diocp_bean;uses  SysUtils,  Classes,  mybean.core.beanFactoryForNoVcl,  uRemoteServerDIOCPImpl in Service\uRemoteServerDIOCPImpl.pas;{$R *.res}begin  beanFactory.RegisterBean(diocpRemoteSvr, TRemoteServerDIOCPImpl).Singleton := true;end.

注册的diocpRemoteSvr插件实现了IRemoteServer接口和IRemoteServerConnector接口,而且该插件为单件模式。其他任何地方调用都只会产生一个连接实例。

type  IRemoteServer = interface(IInterface)    [{20B5F070-461C-41F4-AA0C-E500A36E18E4}]    /// <summary>    ///   执行远程动作    /// </summary>    function Execute(pvCmdIndex: Integer; var vData: OleVariant): Boolean; stdcall;  end;  IRemoteServerConnector = interface(IInterface)    [{65931F56-07BA-42F8-BD5C-7409053F5B2C}]    procedure setHost(pvHost: PAnsiChar);    procedure setPort(pvPort:Integer);    procedure open;  end;

 

 

演示操作窗体:<服务端是13K的成语记录>

image

相应按钮代码:

constructor TfrmMain.Create(AOwner: TComponent);begin  inherited;  // 通过注册的插件ID获取单实例的远程连接操作接口  FRemoteSvr := TMyBeanFactoryTools.getBean(diocpRemoteSvr) as IRemoteServer;end;procedure TfrmMain.btnConnectClick(Sender: TObject);begin  // 打开远程连接,如果打开过可以不用打开,其他插件中可以直接使用  (FRemoteSvr as IRemoteServerConnector).setHost(PAnsiChar(AnsiString(edtHost.Text)));  (FRemoteSvr as IRemoteServerConnector).setPort(StrToInt(edtPort.Text));  (FRemoteSvr as IRemoteServerConnector).open;  ShowMessage(open succ!);end;procedure TfrmMain.btnOpenClick(Sender: TObject);var  vData:OleVariant;  l : Cardinal;begin  vData := mmoSQL.Lines.Text;  l := GetTickCount;  // 在远程打开SQL  if FRemoteSvr.Execute(1, vData) then  begin    self.cdsMain.Data := vData;    Self.Caption := Format(query: count:%d, time:%d,      [self.cdsMain.RecordCount, GetTickCount - l]);  end;end;

 

PS: 其他功能大家自己去实现,该文章写了好几个中午,希望对大家有用。

由于qdac开源项目 >=D2007,所以D7下面不能编译服务端,和diocp_bean.项目(你可以在D2007中编译好diocp_bean和服务端工程,其他插件可以在d7中完成)

 

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

MyBean 轻量级配置开源框架 开源地址

https://git.oschina.net/ymofen/delphi-framework-MyBean

DIOCP3开源地址

https://github.com/ymofen/diocp3

 

qdac项目信息

官方网站:http://www.qdac.cc

官方QQ群:250530692

QDAC项目网址:http://sourceforge.net/p/qdac3

在线源码浏览:http://sourceforge.net/p/qdac3/code/HEAD/tree/

SVN检出地址:

http://svn.code.sf.net/p/qdac3/code/
svn://svn.code.sf.net/p/qdac3/code/

[DIOCP3/MyBean/QDAC开源项目] DataModule-DB例子基于MyBean的插件实例<三层数据库方案>