我使用向导创建了一个独立的Datasnap TCP / IP服务器。我选择了样本方法(echostring和reversestring)。我保存了服务器并运行它。然后我创建了一个客户端应用程序,并使用file-new-other,将ClientModule与ClientClasses单元一起添加到该客户端项目中。在主要表格上。我添加了一个按钮。在按钮的onclick事件处理程序中,我添加了以下代码:
procedure TForm1.Button1Click(Sender: TObject);
begin
if ClientModule1.SQLConnection1.Connected then
begin
Button1.Text := 'Open';
ClientModule1.SQLConnection1.Close;
end
else
begin
Button1.Text := 'Close';
// ClientModule1.SQLConnection1.Open;
ClientModule1.ServerMethods1Client.ReverseString('myteststring');
end;
end;
此处的目的是模拟客户端定期登录和注销服务器而不是保持连接的情况。这对于部署到移动设备的应用程序尤为重要。
你可以看到我注释掉了Connection.Open,因为第一次调用ServerMethods1client会打开连接。生成的代码如下所示:
function TClientModule1.GetServerMethods1Client: TServerMethods1Client;
begin
if FServerMethods1Client = nil then
begin
SQLConnection1.Open;
FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, FInstanceOwner);
end;
Result := FServerMethods1Client;
end;
现在问题出现了。首次单击该按钮时,将打开连接,并调用该方法。在第二次单击按钮时,连接将关闭。 在第3次点击时,会引发异常并且#34;操作失败。连接已关闭"使用TDBXCommand代码引发。
作为解决方法,我尝试了这个:
procedure TForm1.Button1Click(Sender: TObject);
begin
if ClientModule1.SQLConnection1.Connected then
begin
Button1.Text := 'Open';
ClientModule1.SQLConnection1.Close;
ClientModule1.ServerMethods1Client := nil;
end
else
begin
Button1.Text := 'Close';
// ClientModule1.SQLConnection1.Open;
ClientModule1.ServerMethods1Client.ReverseString('myteststring');
end;
end;
这样可以解决问题,因为ClientModule1的FServerMethods1Client实例已重置,因此创建代码会像第一次运行时那样再次运行。
现在唯一的另一个问题是(我正在使用Eurekalog)它会造成内存泄漏。
我做错了什么?在不重新启动应用程序的情况下,重复连接/断开Datasnap服务器的正确方法是什么?
答案 0 :(得分:2)
第一个错误的原因是绑定客户端代理(允许调用服务器方法)的代码与本地SQL连接相关联。请注意创建代理类的调用:
FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, ...)
底层DBExpress连接通过引用传递,代理类使用该连接来调用服务器。您关闭并重新打开了连接,但ServerMethodsClient1正在使用的基础DBExpress连接已被破坏。因此,您收到“连接已关闭”异常。 ServerMethodsClient1正在使用的连接已关闭。您必须像在第二个示例中那样重新创建ServerMethodsClient1。
我无法回答你的第二个问题,因为我认为这是针对ARC的。对于VCL DataSnap应用程序,我会调用ServerMethodsClient1.Free而不是将其设置为nil。基于我对Delphi的ARC实现(全部来自新闻组)非常非常有限的理解,我相信你应该调用ServerMethodsClient1.DisposeOf,因为该类来自TComponent
但我不确定。我相信有人会跳到这里,了解ARC以及破坏对象的正确解决方案而不是内存泄漏。
答案 1 :(得分:-1)
在我的Android FMX实现中,我只调用servermethods来完成工作。 (即我不使用Datasnap数据组件)。 Datasnap架构有太多不受控制的数据传输开销,无法在移动设备上真实地考虑其他任何事情......为了解决它(并且没有内存泄漏),我现在创建TServermethods1Client的本地实例,当我需要它们时在上下文中释放它们:
function TClientModule1.PostTheLog: Boolean;
var
Server: TServerMethods1Client;
begin
Server := TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection);
try
UserID := Server.GetUserID;
...
finally
Server.Free;
end;
end;
现在可以随意连接和断开ClientModule1.SQLConnection1(最好在调用服务器方法之前连接,之后断开连接),不再出现问题。
然后提出了一个问题:在哪个理想世界中,可公开访问的ServerMethods1Client实际上是否有用?