Delphi ADO组件命令超时

Delphi ADO组件命令超时,delphi,timeout,ado,tadoquery,tadodataset,Delphi,Timeout,Ado,Tadoquery,Tadodataset,我对TADOQuery、TADOCommand或TADODataSet的查询执行超时设置有问题(我对每一个都试过)。我有一个微型应用程序,它连接到数据库,定期执行存储过程,结果返回数据集。 我的目标是让这个应用程序始终在线,但我的问题是,当连接断开时,刚刚执行的命令(通过上述组件之一)的超时时间默认为30秒。我一直在寻找解决方案,但没有任何效果。 您能给我一个建议,如何设置CommandTimeout,例如设置为5秒或更好,并说明如何修改ADODB.pas以尊重我自己的超时吗? 对此有许多“解决

我对TADOQuery、TADOCommand或TADODataSet的查询执行超时设置有问题(我对每一个都试过)。我有一个微型应用程序,它连接到数据库,定期执行存储过程,结果返回数据集。 我的目标是让这个应用程序始终在线,但我的问题是,当连接断开时,刚刚执行的命令(通过上述组件之一)的超时时间默认为30秒。我一直在寻找解决方案,但没有任何效果。 您能给我一个建议,如何设置CommandTimeout,例如设置为5秒或更好,并说明如何修改ADODB.pas以尊重我自己的超时吗?

对此有许多“解决方案”,如set DataComponent.Connection.CommandTimeout:=1;但事实上,什么都不管用。我使用的是D2009、MSSQL2005,连接和数据组件都是在线程中动态创建的

最后,我试过的是这个

// protected variable owned and created in the thread with its own connection
var Query_Object: TADODataSet; 

// connection timeout is set to 3 seconds
Query_Object.Connection.ConnectionTimeout := 3;
...

// this piece of code I'm calling periodically in the only one existing thread
...
SQL_Query := 'EXEC my_procedure_which_returns_dataset'

with Query_Object do
  begin
    Close;    
    CommandType := cmdText;
    CommandText := SQL_Query;
    CommandTimeout := 5;             // doesn't affect the timeout
    CursorLocation := clUseServer;   // let the dataset retreives prepared data
    Open;
  end;

// and here I need to get faster than in the default 15 seconds to let the user
// know that the reading takes more than mentioned 5 seconds
...

非常感谢:)

下面是我们将长时间运行的报告的超时设置为300的方法

  //***** Fix setting CommandTimeOut. 
  //      CommandTimeOut "should" get the timeout value from its connection. 
  //      This is not supported in ADODB (using Delphi5)
  TADODataSet(qryReport).CommandTimeout := ADOConnection.CommandTimeout;
编辑

procedure TForm1.btn1Click(Sender: TObject);
const
  SSQL: string =
    'DECLARE    @intLoop int '#13#10
    + 'SET @intLoop = 10 '#13#10
    + 'WHILE @intLoop > 1 '#13#10
    + 'BEGIN '#13#10
    + ' SELECT  @intLoop, GetDate() '#13#10
    + ' WAITFOR DELAY ''00:00:01'' '#13#10
    + ' SELECT  @intLoop = @intLoop -1 '#13#10
    + 'END ';
begin
  qry1.SQL.Text := SSQL;
  TADODataSet(qry1).CommandTimeout := 1;
  qry1.ExecSQL;
end;
在我的开发机器上执行以下代码在1秒后超时

  • 该查询具有到SQLServer生产数据库的connectionstring
  • 脚本(尝试)运行10秒
  • 一秒钟后,我得到一个超时异常
测试

procedure TForm1.btn1Click(Sender: TObject);
const
  SSQL: string =
    'DECLARE    @intLoop int '#13#10
    + 'SET @intLoop = 10 '#13#10
    + 'WHILE @intLoop > 1 '#13#10
    + 'BEGIN '#13#10
    + ' SELECT  @intLoop, GetDate() '#13#10
    + ' WAITFOR DELAY ''00:00:01'' '#13#10
    + ' SELECT  @intLoop = @intLoop -1 '#13#10
    + 'END ';
begin
  qry1.SQL.Text := SSQL;
  TADODataSet(qry1).CommandTimeout := 1;
  qry1.ExecSQL;
end;

我一直使用以下代码在TADOQuery上设置CommandTimeout值。如果您调整类名,它也应该与其他类名一起工作

type 
TADOQueryHack = class(TADOQuery);

...

TADOQueryHack(Qry).CommandTimeout := COMM_TIMEOUT;

当您有长时间运行的查询时,
CommandTimeout
正在启动。有一个
TADOConnection
CommandTimeout
属性,但它不起作用。您必须使用
TADODataSet
CommandTimeout

如果服务器不可用,您的问题是“连接丢失”,您需要指定
TADOConnection
组件的
ConnectionTimeout
。默认值为控件返回应用程序前15秒

编辑1我想我发现了CommandTimeout不起作用的情况。我已经在一张很大的桌子上测试过了。返回所有行需要几分钟的时间。如果我的存储过程没有
从BigTable
中选择*。至少我没有耐心等它结束。但是,如果查询看起来像这样,
select*from BigTable order by Col1
,并且
Col1
上没有索引,那么CommandTimout将按预期工作

在SSMS中运行这两个查询时,它们之间的差异是显而易见的。第一个开始立即返回行,第二个在返回行之前需要“思考”。当SQL Server找到它需要的行并开始返回它们时,CommandTimeout不起作用


如果将
CursorLocation
设置为
clUseServer
CommandTimeout
将按预期在两个查询中工作

+1谢谢你的提示,但它不起作用。无论如何,我需要相反的情况-尽快获得响应,但即使我根据您的建议将CommandTimeout设置为5,我仍在等待30秒。@daemon_x,将其设置为300对我们有效,但我们尚未尝试将其设置为<30。如果我有时间,我会检查并报告我的发现。@daemon_x:我已经用适合我的脚本更新了答案。如果这对你不起作用,那就有别的问题了。如果是这样,您就有了一个起点来找出与实际代码的差异。@Lieven-是的,这可能适用于ExecSQL,但我正在尝试使用open方法打开数据集。也就是说,我想执行存储过程,它返回一个resultset。目前,我谈到了TADODataSet对象(请参阅我更新的问题)。这只是一个示例。对于我们的报告,我们使用
Open
io
ExecSQL
,并遵守命令超时。这个例子给你一个暂停时间吗?你试过了吗?当您将其更改为使用Open io ExecSQL(并将sql语句更改为需要时间的语句)时,它是否有效?您是对的,它是15秒,但我已将分配的TADOConnection的ConnectionTimeout设置为3秒,但我仍然在15秒后重新获得控件。@daemon_x:更新了答案,并提供了更多发现。我可以重新创建您正在经历的。它工作正常,我在其他方面犯了一个错误(与ADO无关),经过更正,我在TADODataSet.CommandTimeout+TADODataSet.Connection.ConnectionTimeout之后确实得到了超时。作为一个解决方案也被接受,因为光标位置备注:)谢谢您的时间