ADO компоненты CommandTimeout - PullRequest
7 голосов
/ 22 февраля 2011

У меня проблема с настройками тайм-аута выполнения запроса с помощью TADOQuery, TADOCommand или TADODataSet (я пробовал с каждым).У меня есть крошечное приложение, которое подключается к базе данных и периодически выполняет хранимые процедуры, которые возвращают набор данных в результате .Моя цель - поддерживать это приложение всегда в сети, но моя проблема в том, что при потере соединения тайм-аут только что выполненной команды (через один из упомянутых компонентов) по умолчанию составляет 30 секунд.Я искал решение, но ничего не работает. Не могли бы вы дать мне совет, как установить CommandTimeout, например, на 5 секунд или лучше сказать, как изменить ADODB.pas для соблюдения моего собственного времени ожидания, пожалуйста?

Их было много "Решения "для этого, как установить 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
...

Большое спасибо:)

Ответы [ 3 ]

5 голосов
/ 23 февраля 2011

CommandTimeout включается, когда у вас есть долго выполняющиеся запросы. Есть свойство CommandTimeout TADOConnection, но оно не работает. Вместо этого вы должны использовать CommandTimeout из TADODataSet.

Если сервер недоступен, в вашем вопросе говорится «соединение потеряно», вам необходимо указать ConnectionTimeout компонента TADOConnection. По умолчанию это 15 секунд, прежде чем контроль возвращается в ваше приложение.

Редактировать 1 Мне кажется, я обнаружил ситуацию, когда CommandTimeout не работает. Я проверил это на действительно большом столе. Требуется несколько минут, чтобы вернуть все строки. Если моя хранимая процедура делает select * from BigTable, тайм-аут запроса никогда не происходит. По крайней мере, я не был достаточно терпелив, чтобы ждать. Но если запрос выглядит следующим образом select * from BigTable order by Col1, а индекс Col1 отсутствует, CommandTimout работает, как и ожидалось.

Разница между этими двумя запросами очевидна при запуске их в SSMS. Первый начинает немедленно возвращать строки, а второй должен «подумать» об этом, прежде чем он вернет строки. Когда SQL Server обнаружил нужные строки и начал их возвращать, CommandTimeout не работает.

Если вы установите CursorLocation на clUseServer, CommandTimeout будет работать, как и ожидалось, для обоих запросов.

1 голос
/ 22 февраля 2011

Ниже приводится то, что мы используем для установки времени ожидания для наших долгосрочных отчетов.

  //***** 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;

Редактировать

Выполнение следующего фрагмента кода в моей разработкеВремя ожидания компьютера истекает через 1 секунду.

  • Запрос содержит строку подключения к нашей производственной базе данных SQLServer.
  • Сценарий (пытается) выполняется в течение 10 секунд
  • Послеодну секунду я получаю исключение TimeOut

Test

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;
0 голосов
/ 22 февраля 2011

Я всегда использовал следующий код для установки значения CommandTimeout в TADOQuery.Если вы измените имя класса, оно также должно работать и с другими.

type 
TADOQueryHack = class(TADOQuery);

...

TADOQueryHack(Qry).CommandTimeout := COMM_TIMEOUT;
...