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

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

【说明】

这个例子答应大家很久了,一直没有时间弄,现在正式结合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/

目录
相关文章
|
2月前
|
存储 监控 安全
数据库多实例的部署与配置方法
【10月更文挑战第23天】数据库多实例的部署和配置需要综合考虑多个因素,包括硬件资源、软件设置、性能优化、安全保障等。通过合理的部署和配置,可以充分发挥多实例的优势,提高数据库系统的运行效率和可靠性。在实际操作中,要不断总结经验,根据实际情况进行调整和优化,以适应不断变化的业务需求。
|
4月前
|
消息中间件 canal 缓存
项目实战:一步步实现高效缓存与数据库的数据一致性方案
Hello,大家好!我是热爱分享技术的小米。今天探讨在个人项目中如何保证数据一致性,尤其是在缓存与数据库同步时面临的挑战。文中介绍了常见的CacheAside模式,以及结合消息队列和请求串行化的方法,确保数据一致性。通过不同方案的分析,希望能给大家带来启发。如果你对这些技术感兴趣,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
274 6
项目实战:一步步实现高效缓存与数据库的数据一致性方案
|
4月前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
8天前
|
存储 缓存 NoSQL
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
|
2月前
|
负载均衡 网络协议 数据库
选择适合自己的数据库多实例负载均衡技术
【10月更文挑战第23天】选择适合自己的数据库多实例负载均衡技术需要全面考虑多种因素。通过深入的分析和评估,结合自身的实际情况,能够做出明智的决策,为数据库系统的高效运行提供有力保障。
130 61
|
2月前
|
存储 负载均衡 监控
数据库多实例的深入解析
【10月更文挑战第24天】数据库多实例是一种重要的数据库架构方式,它为数据库的高效运行和灵活管理提供了多种优势。在实际应用中,需要根据具体的业务需求和技术环境,合理选择和配置多实例,以充分发挥其优势,提高数据库系统的性能和可靠性。随着技术的不断发展和进步,数据库多实例技术也将不断完善和创新,为数据库管理带来更多的可能性和便利。
130 57
|
2月前
|
SQL Java 数据库连接
深入 MyBatis-Plus 插件:解锁高级数据库功能
Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。
415 26
深入 MyBatis-Plus 插件:解锁高级数据库功能
|
1月前
|
存储 Oracle 关系型数据库
数据库数据恢复—ORACLE常见故障的数据恢复方案
Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。
121 11
|
1月前
|
SQL 关系型数据库 MySQL
数据库数据恢复—Mysql数据库表记录丢失的数据恢复方案
Mysql数据库故障: Mysql数据库表记录丢失。 Mysql数据库故障表现: 1、Mysql数据库表中无任何数据或只有部分数据。 2、客户端无法查询到完整的信息。
|
2月前
|
缓存 关系型数据库 MySQL
高并发架构系列:数据库主从同步的 3 种方案
本文详解高并发场景下数据库主从同步的三种解决方案:数据主从同步、数据库半同步复制、数据库中间件同步和缓存记录写key同步,旨在帮助解决数据一致性问题。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
高并发架构系列:数据库主从同步的 3 种方案

热门文章

最新文章