Datasnap查询出错,即使客户端断开连接,也会在SQL上保持连接

时间:2015-03-26 14:01:05

标签: delphi datasnap

在Delphi Datasnap服务器中,如果在sql查询或存储过程中发生某种错误,即使客户端与Datasnap服务器断开连接,SQL Server也会保持连接处于活动状态,直到我关闭Datasnap服务器。 它很容易重现,只需从向导创建Datasnap服务器。放一些肯定会返回错误的选择查询,例如。 "从用户中选择bud_beer" :) 从向导创建客户端,TClientDataSet连接到加载啤酒的提供者:) 现在打开企业管理器,按服务器和用户过滤,并观察连接。 打开ClientDataSet,当然会出错。 您将在Enterprise Manager中看到连接。关闭客户端,连接将保持不变,并在关闭datasnap服务器时消失。 如果打开了更多客户端,那么更多连接将停留在SQL Server中,直到datasnap服务器关闭为止。

来自服务器的来源:

unit ServerContainerUnit1;

interface

uses System.SysUtils, System.Classes,
  Datasnap.DSTCPServerTransport,
  Datasnap.DSServer, Datasnap.DSCommonServer,
  Datasnap.DSAuth, IPPeerServer;

type
  TServerContainer1 = class(TDataModule)
    DSServer1: TDSServer;
    DSTCPServerTransport1: TDSTCPServerTransport;
    DSServerClass1: TDSServerClass;
    procedure DSServerClass1GetClass(DSServerClass: TDSServerClass;
      var PersistentClass: TPersistentClass);
    procedure DSServer1Connect(DSConnectEventObject: TDSConnectEventObject);
    procedure DSServer1Disconnect(DSConnectEventObject: TDSConnectEventObject);
  private
    { Private declarations }
  public
  end;

var
  ServerContainer1: TServerContainer1;

implementation

uses Winapi.Windows, ServerMethodsUnit1, Unit2;

{$R *.dfm}

procedure TServerContainer1.DSServer1Connect(
  DSConnectEventObject: TDSConnectEventObject);
begin
  LogInfo('Connected');
end;

procedure TServerContainer1.DSServer1Disconnect(
  DSConnectEventObject: TDSConnectEventObject);
begin
  LogInfo('Disconnected');
end;

procedure TServerContainer1.DSServerClass1GetClass(
  DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
  PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;

end.

和dfm:

object ServerContainer1: TServerContainer1
  OldCreateOrder = False
  Height = 271
  Width = 415
  object DSServer1: TDSServer
    OnConnect = DSServer1Connect
    OnDisconnect = DSServer1Disconnect
    Left = 96
    Top = 11
  end
  object DSTCPServerTransport1: TDSTCPServerTransport
    Server = DSServer1
    Filters = <>
    Left = 96
    Top = 73
  end
  object DSServerClass1: TDSServerClass
    OnGetClass = DSServerClass1GetClass
    Server = DSServer1
    Left = 200
    Top = 11
  end
end

服务器方法:

unit ServerMethodsUnit1;

interface

uses System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth,
  Data.DBXMSSQL, Data.FMTBcd, Data.DB, Data.SqlExpr, Datasnap.Provider;

type
  TServerMethods1 = class(TDSServerModule)
    SQLConnection1: TSQLConnection;
    SQLDataSet1: TSQLDataSet;
    DataSetProvider1: TDataSetProvider;
    procedure DSServerModuleCreate(Sender: TObject);
    procedure DSServerModuleDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

{var
  ServerMethods1: TServerMethods1;}

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}
uses Unit2;
{$R *.dfm}

procedure TServerMethods1.DSServerModuleCreate(Sender: TObject);
begin
  LogInfo('Created methods');
end;

procedure TServerMethods1.DSServerModuleDestroy(Sender: TObject);
begin
  LogInfo('Destroyed methods');
end;

end.

和dfm:

object ServerMethods1: TServerMethods1
  OldCreateOrder = False
  OnCreate = DSServerModuleCreate
  OnDestroy = DSServerModuleDestroy
  Height = 445
  Width = 561
  object SQLConnection1: TSQLConnection
    DriverName = 'MSSQL'
    LoginPrompt = False
    Params.Strings = (
      'SchemaOverride=%.dbo'
      'DriverUnit=Data.DBXMSSQL'

        'DriverPackageLoader=TDBXDynalinkDriverLoader,DBXCommonDriver180.' +
        'bpl'

        'DriverAssemblyLoader=Borland.Data.TDBXDynalinkDriverLoader,Borla' +
        'nd.Data.DbxCommonDriver,Version=18.0.0.0,Culture=neutral,PublicK' +
        'eyToken=91d62ebb5b0d1b1b'

        'MetaDataPackageLoader=TDBXMsSqlMetaDataCommandFactory,DbxMSSQLDr' +
        'iver180.bpl'

        'MetaDataAssemblyLoader=Borland.Data.TDBXMsSqlMetaDataCommandFact' +
        'ory,Borland.Data.DbxMSSQLDriver,Version=18.0.0.0,Culture=neutral' +
        ',PublicKeyToken=91d62ebb5b0d1b1b'
      'GetDriverFunc=getSQLDriverMSSQL'
      'LibraryName=dbxmss.dll'
      'VendorLib=sqlncli10.dll'
      'VendorLibWin64=sqlncli10.dll'
      'HostName=xxxx'
      'Database=xxxx'
      'MaxBlobSize=-1'
      'LocaleCode=0000'
      'IsolationLevel=ReadCommitted'
      'OSAuthentication=False'
      'PrepareSQL=True'
      'User_Name=xxxxx'
      'Password=xxxxx'
      'BlobSize=-1'
      'ErrorResourceFile='
      'OS Authentication=False'
      'Prepare SQL=False')
    Left = 56
    Top = 40
  end
  object SQLDataSet1: TSQLDataSet
    CommandText = 
      'select bud_beer from users'
    MaxBlobSize = -1
    Params = <>
    SQLConnection = SQLConnection1
    Left = 56
    Top = 104
  end
  object DataSetProvider1: TDataSetProvider
    DataSet = SQLDataSet1
    Left = 140
    Top = 104
  end
end

util的

unit Unit2;

interface
procedure LogInfo(line: string);

implementation

uses Unit1, System.SysUtils;

procedure LogInfo(line: string);
begin
  Form1.Memo1.Lines.Add(DateTimeToStr(Now)+' '+line);
  Form1.Memo1.Lines.Add('');
end;

end.

和客户:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, DBXDataSnap, IPPeerClient,
  Data.DBXCommon, Vcl.StdCtrls, Vcl.Grids, Vcl.DBGrids, Data.DB,
  Datasnap.DBClient, Datasnap.DSConnect, Data.SqlExpr;

type
  TForm1 = class(TForm)
    dspcCommon: TDSProviderConnection;
    ClientDataSet1: TClientDataSet;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    Button1: TButton;
    SQLConnection1: TSQLConnection;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
uses proxy;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ClientDataSet1.Active := true;
end;

end.
  1. 问题是:为什么会这样?我怎么能避免它?
  2. 谢谢!

0 个答案:

没有答案