有两个工作线程A和B,在程序运行期间,每接收到一次数据请求,就调用函数ExecuteQuery,往同一个数据库表ws_source里写数据。任一个线程调用ExecuteQuery时,都会动态创建一个临时的TADOConnection对象,执行SQL完毕之后,再将它释放。
/// <summary>
/// 执行返回受影响的行数
/// </summary>
function ExecuteNoQuery(ACommandText:string):Integer;var
  Query: TADOQuery;
  ADOConnection : TADOConnection;
begin
  ADOConnection := GetConnection();
  try
    Query := TADOQuery.Create(Application); // 问题:数据高峰时,会发生创建失败
    try
      With Query do
      begin
        Connection := ADOConnection;
        Close;
        SQL.Clear;
        SQL.Add(ACommandText);
        try
          Result := ExecSQL;
        except
          on E:EOleException do
          begin
            // 如失去连接则重新连接
             if (CompareText(E.Message,'Connection failure')=0) or
              (CompareText(E.Message,'连接失败')=0) then
            begin
              ADOConnection.Connected := False;
              ADOConnection.Connected := True;
              Result := ExecSQL;
            end
            else
            begin
              raise;
            end;
          end
          else
          begin
            raise;
          end;
        end;
      end;
    finally
      Query.Free;
    end;
  finally
    ReleaseConnection(ADOConnection);
  end;
end;
现在的问题是,一般在每天的早上9点~10点会有一次数据高峰期,这时就会频繁发生TADOQuery创建失败的情况,导致数据无法写入数据库。

解决方案 »

  1.   

    有个想法:在程序启动的时候,创建一个全局的TADOQuery对象,供那两个工作线程使用,在程序关闭的时候再销毁它。因为它被两个工作线程共同使用,所以要加资源保护锁。
    因为,程序里还有其他的线程要访问这个数据库的其他表,其他线程会不会因为程序运行期间始终存在一个全局TADOQquery对象,而无法创建另外的TADOQquery对象?
      

  2.   

    尝试了一下加入重试机制,当创建TADOQquery失败时,重新调用ExecuteQuery,最多允许5次重试。结果在5次里面竟然还是没有一次成功。郁闷啊。
      

  3.   

    捕获到的错误如下:
    Access violation at address 00490057 in module 'MonitorServer.exe'. Read of address F1751E1D
    不知道从这里能看出什么呢?
      

  4.   

    这几天查了很多资料。
    看到网上这么说(链接地址http://www.myexception.cn/delphi/264643.html):ADOQquery.Free后,由于ADO本身的特性,这个ADOQquery对应的数据库连接要过一段时间才会被释放掉。如果在短时间内大量地创建和释放ADOQquery,就会有大量的数据库连接来不及释放掉,导致后面无法创建ADOQquery。当数据高峰过后,堆积的数据库连接会逐渐被释放掉,所以后面又可以创建ADOQquery了。这个说法,很好解释了我的问题。但如何解决这个问题呢?
      

  5.   


    多谢两位。
    后来把这问题解决了。
    频繁地创建和释放是没关系的,主要是“Query := TADOQuery.Create(Application);
    ”这句有问题,因为创建TADOQuery的对象的Parent是Application,所以当手动释放时,一般要过一段时间才真正被释放。将它改为“Query := TADOQuery.Create(nil);
    ”,问题就解决了。