ADOConnection ADOQuery CommandTimeout,覆盖顺序(如果有的话)

ADOConnection ADOQuery CommandTimeout , Override Order ( if at all )

到达此处 Delphi 10.4.2。一个 ADOConnection 和一个 ADOQuery .

ADOConnection 使用 OleDB (UDL) 连接到 MSSQL。我已经离开了 CommandTimeout 30 。 现在我将 ADOQuery 放在这个表单上,将它的 Connection 属性 设置为 ADOConnection 。所有其他值均为默认值,CommandTimeout 为 30。

现在假设我们有一个非常大的 table 超时。使用默认的 30 秒。

我的问题是:

如果我将 ADOQuery CommandTimeout 设置为 600,它就可以工作 但如果我只将 ADOConnection CommandTimeout 设置为 600,它仍然会超时

如果 ADOConnection 上的 CommandTimeout 不简单地将它的值传播到它的关联组件(当然直到我覆盖它们),它有什么目的?

谢谢。

编辑 1:

ADOConnection CommandTimeout 是否实际用于 ADOConnection 为建立连接而必须执行的某些后台任务? 例如,如果我在 IDE 中激活它,然后有一个 ADOStoredProcedure 并且我想列出服务器上所有可用的存储过程,它会使用此超时吗?

根据 Microsoft 每个 ADO 对象尊重它自己的 CommandTimeout:

The CommandTimeout setting on a Connection object has no effect on the CommandTimeout setting on a Command object on the same Connection; that is, the Command object's CommandTimeout property does not inherit the value of the Connection object's CommandTimeout value.

我做了一个小MRE(使用Delphi10.3)来证明这一点:

program SO69733529;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  ActiveX,
  AdoDb,
  System.SysUtils;

procedure TestADOCommandTimeout;

var
  Conn : TADOConnection;
  Qry  : TADOQuery;
  SQLDelay : Integer;

begin
 Conn := TADOConnection.Create(nil);
 Qry := TADOQuery.Create(nil);
 try
  Conn.LoginPrompt := False;
  Conn.ConnectionString := 'Provider=SQLOLEDB.1;Data Source=localhost\sqlexpress;Initial Catalog=TestCustomer;Integrated Security = SSPI;';
  Conn.Connected := True;
  Qry.Connection := Conn;
  Writeln('Connected to DB');
  SQLDelay := 10;
  Conn.CommandTimeout := 5;
  try
   Writeln(Format('Waiting for %d seconds, connection timeout is %d seconds', [SQLDelay, Conn.CommandTimeout]));
   Conn.Execute(Format('WAITFOR DELAY ''00:00:%.2d''', [SQLDelay]));
   Writeln('No Timeout');
  except
   on E: Exception do
    Writeln(E.ClassName, ': ', E.Message);
  end;
  Qry.CommandTimeout := 30;
  try
   Writeln(Format('Waiting for %d seconds, query timeout is %d seconds, connection timeout is %d seconds', [SQLDelay, Qry.CommandTimeout, Conn.CommandTimeout]));
   Qry.SQL.Text := Format('WAITFOR DELAY ''00:00:%.2d''', [SQLDelay]);
   Qry.ExecSQL;
   Writeln('No Timeout');
  except
   on E: Exception do
    Writeln(E.ClassName, ': ', E.Message);
  end;
  // now redo the same test but with connection commandtimeout same as qry timeout
  Qry.CommandTimeout := 15;
  Conn.CommandTimeout := Qry.CommandTimeout;
  try
   Writeln(Format('Waiting for %d seconds, query timeout is %d seconds, connection timeout is %d seconds', [SQLDelay, Qry.CommandTimeout, Conn.CommandTimeout]));
   Qry.SQL.Text := Format('WAITFOR DELAY ''00:00:%.2d''', [SQLDelay]);
   Qry.ExecSQL;
   Writeln('No Timeout');
  except
   on E: Exception do
    Writeln(E.ClassName, ': ', E.Message);
  end;    
 finally
  Qry.Free;
  Conn.Free;
 end;
end;

begin
  try
   try
    CoInitialize(nil);
    TestADOCommandTimeout;
   finally
     CoUninitialize;
   end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
 Readln;
end.

输出:

 Connected to DB Waiting for 10 seconds, connection timeout is 5 seconds
 EOleException: Query timeout expired 
 Waiting for 10 seconds, query timeout is 30 seconds, connection timeout is 5 seconds  
 No Timeout 
 Waiting for 10 seconds, query timeout is 15 seconds, connection timeout is 15 seconds 
 No Timeout