Delphi Datasnap查询中出错,即使客户端断开连接,仍将连接保留在SQL上

Delphi Datasnap查询中出错,即使客户端断开连接,仍将连接保留在SQL上,delphi,datasnap,Delphi,Datasnap,在Delphi Datasnap server中,如果sql查询或存储过程中发生某种错误,sql server将保持连接处于活动状态,即使客户端与Datasnap server断开连接,直到我关闭Datasnap server。 它很容易复制,只需从向导中创建Datasnap服务器。放置一些将返回错误的select查询,例如从用户处选择bud_beer: 还可以从向导创建客户端,将TClientDataSet连接到加载啤酒的提供程序: 现在打开企业管理器,按服务器和用户筛选,并观察连接。 打开C

在Delphi Datasnap server中,如果sql查询或存储过程中发生某种错误,sql server将保持连接处于活动状态,即使客户端与Datasnap server断开连接,直到我关闭Datasnap server。 它很容易复制,只需从向导中创建Datasnap服务器。放置一些将返回错误的select查询,例如从用户处选择bud_beer: 还可以从向导创建客户端,将TClientDataSet连接到加载啤酒的提供程序: 现在打开企业管理器,按服务器和用户筛选,并观察连接。 打开ClientDataSet,当然会出现错误。 您将在Enterprise manager中看到该连接。关闭客户端后,连接将保持,并在关闭datasnap服务器时消失。 若打开了更多的客户端,那个么在关闭datasnap服务器之前,SQL server中会有更多的连接中断

来自服务器的源:

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
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
和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
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
客户:

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.
问题是:为什么会发生这种情况?我怎样才能避免呢?
谢谢大家!

企业管理器是:Microsoft SQL Server Studio保持数据库连接打开通常是一件好事-它将加快响应速度。查询失败后,下一个可以工作。如果您需要不同的管理,您必须在Datasnap服务器级别处理一些错误,客户端几乎不知道背后的数据库服务器,甚至可能根本没有数据库服务器。哇,那么您的意思是Datasnap服务器没有关闭与SQL server实例的连接,因为对它的一个查询,引发异常?@nolaspeaker,是的,没错。如果启动客户端4次,即使关闭客户端,SQL Server上也会出现4个错误和4个连接。连接将保留在服务器上,直到datasnap服务器关闭。这是100%合理的。在您的datasnap客户端通过关闭客户端到的TSQL连接来断开连接之前,datasnap服务器将保持TCP/IP连接及其与数据库的关联连接处于打开状态。为什么它必须做一些你没有要求它做的事情?作为一名开发人员,您的工作就是亲自应对这种情况,并决定您希望服务器/客户机如何工作。如果要在客户端引发异常时断开连接,请在客户端自己捕获它,然后尝试…exception…end并执行TSqlConnection。关闭自己。