分享

真三层?假三层?

 quasiceo 2017-03-20

需要从两方面来说:

一方面,需要稳定、强大、开发简便、维护方便的“服务端业务容器”,有的又称“软总线”、“插件框架”、“插件容器”等等;

另一方面,客户端,则需要对应封装到位、适用面广、使用简单的调用手段——Delphi VCL控件/FireMonkey控件/JsonRPC/XmlRPC/AJAX等。


在这方面,QuickBurro自然也是走在前列,若干年前就已经很强大,如今更是:

一、服务端支持C/S三层插件、Web插件、移动服务插件、WebSocket服务插件等多种类型的插件;支持单线程/多线程调用方式;支持同步/异步调用模式;支持计划任务形式的主动激发;支持立即返回/驻留模式;支持预加载/延迟卸载机制;支持插件API入口注册与横向调用;支持调用大量的主服务API函数;支持热插拔/远程插拔;支持HTTP/HTTPS/TCP/WebSocket多种通信协议...

二、客户端控件:VCL下提供专门的基于TCP协议和HTTP协议的RPC控件TDllPlugin、提供基于HTTPS实现的Web插件调用控件TQBHttps,只要给出服务端部署的插件名、设定好控件属性、准备好调用参数,就可以方便调用,调用结果也可以方便进行反序列化处理;  FireMonkey下,提供TMBRpc/TMBHttps两个专门进行远过程调用的控件,也一样能轻松进行BinaryRPC/JsonRPC/XmlRPC等调用;  而Web前端,通过AJAX进行RPC调用,一样简单方便。

三层的概念一直有争议。我个人的看法是从负载均衡,数据库隔离来说,三层有它
的价值。至于传SQL也未尝不可,只是要防止sql注入的问题。
曾有一个时期,言必称三层,把一些简单的局域网应用也硬生生抽一个三层出来,我觉得还不如直接传sql呢。
倒是web程序就是天然的三层,你不会在客户端直接传sql吧。
我觉得要考虑的是用三层解决什么问题。而不是为三层而三层

我觉得要考虑的是用三层解决什么问题?我认为主要是解决数据库连接池和网络安全域两方面的考虑,兼顾两层、三层语法尽量一直(两层易于改为三层),中间层只转发sql而不进行逻辑编程(降低程序复杂度、避免总改中间层而出现bug),没有上真三层、假三层之分。
http://download.csdn.net/detail/runsheng678/4812549 以前的例子,已改到Delphi 10 seattle下了

1、业务逻辑经常变而接口形式不变的、或后续可能有新的替代方案的处理过程
2、需要与大量数据打交道、不适合客户端进行的处理过程(比如汇总、报表生成等)
3、需要加强安全性控制、保护知识产权等权益的处理过程
4、需要排队处理的业务逻辑
5、需要与服务端数据库之外的其他资源有交互的过程
6、相对通用、适合服务端封装为可复用模块的
7、涉及服务端系统集成、与周边系统有接口的业务
8、需要服务端主动处理并反向推送信息给客户端的任务
9、服务端实现对提高系统性能、减少消耗、提高可靠性有利的业务逻辑
...
----------
类似这些,我都会做服务端业务逻辑模块,客户端来调用。

至于是否客户端写SQL语句,感觉没必要纠结,非常简单明确的业务处理,没必要迂腐地要弄个专用的服务端模块再来调用实现,毕竟研发成本也是重要的考虑因素。

而注入什么的,对于编译型开发工具Delphi来说,感觉不是个很严重的问题。
----------------------------------------------

我的做法,是把 SQL语句写在 服务器端(其实是保存到数据库中);

客户端只需要 传递一个 序号(对应某SQL语句在数据表的序号),和一些参数传到服务器端就好。其它的交给服务器处理了,然后再把结果返回来;

例从服务器获取数据:

function dm_sys.GetData(const SQL_XH: Integer ;Param:array of string): _Recordset;
var
   V,SendV:OLEVariant;
   i,n : Integer;
   AR:_Recordset;
   AStream:_Stream;
   MS1:TMemoryStream;
   P:Pointer;
begin 
  n := Length(Param);
  SendV := VarArrayCreate([0,n],varOleStr);
  for I := Low(Param) to High(Param) do SendV[i] := Param[i];
  try
    V:=Disp_Fun.ProF_ReadAdoData2(SQL_XH,n,SendV);
    MS1:=TMemoryStream.Create;
    try
      MS1.Size:=VarArrayHighBound(V,1)+1;
      P:=VarArrayLock(V);
      try
        Move(P^,MS1.Memory^,MS1.Size);
      finally
        VarArrayUnLock(V);
      end;
      V:=VarArrayCreate([0,MS1.Size-1],varByte);
      P:=VarArrayLock(V);
      try
        Move(MS1.Memory^,P^,MS1.Size);
      finally
        VarArrayUnLock(V);
      end;
    finally
     FreeAndNil(MS1);
    end;
    AStream:=CoStream.Create;
    AStream.Open(EmptyParam,adModeUnknown,adOpenStreamUnspecified, '', '');
    AStream.Type_:=adTypeBinary;
    AStream.Write(V);

    AR:=_Recordset(CoRecordset.Create);
    AStream.Position:=0;
    AR.Open(AStream,EmptyParam,adOpenUnspecified, adLockUnspecified, -1);
    Result:=ADOInt._Recordset(AR);
  except
   on E:Exception do begin
     ShowErrorMessage(E.Message);
   end;
  end; 
 

end;

如果有那种特殊情况在要客户端传递SQL语句的,就加密传去就好。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多