马上周末了,趁着下午这会儿回顾一下这几天对旧项目的升级过程,一些重要但不常用的东西记录下来是很有必要的。其中一个项目中对KBMMW的远程数据通讯方式做了改进,利用SampleService/SampleClient方式传输数据集,以增加对底层数据通讯的可控性。
服务端代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
type TkbmMWSimpleService1 = class (TkbmMWSimpleService)
private
{ Private declarations }
protected
{ Protected declarations }
function ProcessRequest( const Func: string ; const ClientIdent:TkbmMWClientIdentity; const Args: array of Variant):Variant; override;
function PerformOpenSQL(ClientIdent:TkbmMWClientIdentity; const Args: array of Variant):Variant; virtual;
public
{ Public declarations }
{$IFNDEF CPP}class{$ENDIF} function GetFlags:TkbmMWServiceFlags; override;
end ;
//...省略 function TkbmMWSimpleService1 . ProcessRequest( const Func: string ; const ClientIdent:TkbmMWClientIdentity; const Args: array of Variant):Variant;
var AFunc: string ;
begin AFunc:=UpperCase(Func);
if AFunc= 'OPENSQL' then
Result:=PerformOpenSQL(ClientIdent,Args)
else Result:= inherited ProcessRequest(Func,ClientIdent,Args);
end ;
function TkbmMWSimpleService1 . PerformOpenSQL(ClientIdent:TkbmMWClientIdentity; const Args: array of Variant):Variant;
var sqlStr: string ;
aQuery: TUniQuery;
aconn: TkbmMWUNIDACConnection;
memTable: TkbmMemTable;
aStreamFormat: TkbmBinaryStreamFormat;
begin Result := 0 ;
sqlStr:=args[ 0 ];
aQuery := TUniQuery . Create( nil ); //uniquery,和两层的用法一样
aQuery . Options . QueryRecCount := True ;
aconn := TkbmMWUNIDACConnection(DMunt . kbmMWUNIDACConnectionPool1 . GetBestConnection( True , 0 , nil , 10000 )); //取连接池中的连接
if aconn = nil then
begin
kbmMWRaiseServerException( '无可用的数据库连接' );
Exit;
end ;
aQuery . Connection := aconn . Database;
aQuery . SQL . Text := sqlStr;
if (mainform . PAL_mode_01 . Visible) then
LogIOer . AddShow(ClientIdent . Username+ '执行SQL查询:' +aQuery . SQL . Text, 0 );
memTable := TkbmMemTable . Create( nil );
aStreamFormat := TkbmBinaryStreamFormat . Create( nil );
memTable . DefaultFormat := aStreamFormat;
memTable . IndexFieldNames := '' ;
memTable . SortFields := '' ;
memTable . MasterSource := nil ;
try
try
aQuery . Open; //查询
Result := aQuery . RecordCount; //返回记录条数
except
on E:Exception do
begin
kbmMWRaiseServerException(E . Message+ ',异常语句:' +aQuery . SQL . Text); //抛异常到客户端
Exit;
end ;
end ;
memTable . LoadFromDataSet(aQuery,[mtcpoStructure,mtcpoProperties]); //复制数据集进KbMemTable
memTable . SaveToStreamViaFormat(ResultStream,aStreamFormat); //按照指定流格式存入结果流ResultStream
finally
aconn . UnlockConnection;
aQuery . Free;
memTable . Free;
aStreamFormat . Free;
end ;
end ;
|
客户端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
function openSql(Sqlstr: string ; var Ds:TDataSet; var Rs: string ): integer ;stdcall;
var
args: array [ 0..1 ] of Variant;
begin
Result := 0 ;
Rs := '执行成功' ;
if assigned(kbmMWSimpleClient1) then
begin
try
args[ 0 ]:= Sqlstr; //SQL语句
Result := kbmMWSimpleClient1 . Request( 'TkbmMWSimpleService1' , '' , 'openSql' ,args); //SimpleClient执行请求
kbmMemTable . EmptyTable; //清空内存表
kbmMemTable . LoadFromStreamViaFormat(kbmMWSimpleClient1 . ResultStream,aStreamFormat); //将结果流复制进内存表
ds := kbmMemTable; //返回dataset(kbmMemTable继承自Tdataset)
except
on E:Exception do
begin
Result := - 1 ;
rs := errorInfo(E . Message);
if FIsLog then Writelog(rs);
end ;
end ;
end
else
begin
Result := - 1 ; //未执行初始化操作
Rs := '远程数据通讯接口未执行初始化操作'
end ;
end ;
|
核心代码就这些,相信用到的人能够看明白。同理,可以利用这种方式实现二进制文件流(如:图像等)的传输,不再赘述。
另外,有一个小问题折磨了我一下午,提醒大家一下,希望大家不要像我一样粗心:
有两个类:TkbmBinaryStreamFormat(kbmMemBinaryStreamFormat.pas)、TkbmMWBinaryStreamFormat(kbmMWBinaryStreamFormat.pas)很容易混淆(正确用法见上述代码),而且一旦混淆,会造成KbmMeMTable在流的处理过程中出错。
http://www.pfeng.org/archives/385