ahhjgh 
 
等级: 
可用分等级:长工 
总技术分:409 
总技术分排名:40519  
发表于:2009-06-12 08:41:137楼 得分:0 
这个问题我也碰到过,最后是这么解决的,检测过程贴出,你自己参考: 
procedure TForm2.Timer4Timer(Sender: TObject); 
var 
  strError:string; 
  ConnStr,ServerIp:string; 
  tmpStrList :TStringList; 
Const 
  CONNECTABORT_SQLSERVER1 = '08S0 '; //连接失败的错误号(SQLSERVER) 在简体版本下,显示不出最后一位 
  CONNECTABORT_SQLSERVER2 = '08S01'; //连接失败的错误号(SQLSERVER) 
  CONNECTFAULT_SQLSERVER = '08001'; //连接不上服务器的的错误号(SQLSERVER) 
begin 
  if Form1.ADOConnection1.Errors.Count >0 then 
  begin 
    strError := Form1.ADOConnection1.Errors.Item[0].SQLState; 
    if (strError = CONNECTABORT_SQLSERVER1)or(strError = CONNECTABORT_SQLSERVER2)or(strError = CONNECTFAULT_SQLSERVER) then 
    begin 
      Timer2.Enabled := false; 
      Timer3.Enabled := false;       ConnStr := Form1.ADOConnection1.ConnectionString; 
      tmpStrList := Common.SplitString(ConnStr,';'); 
      ServerIp := tmpStrList.Values['Data Source']; 
      tmpStrList.Free;       if PingServer(ServerIp) then 
      begin 
        Form1.ADOConnection1.Connected := false; 
        Try 
          Form1.ADOConnection1.Open; 
          Timer2.Enabled := true; 
          Timer3.Enabled := true; 
        Except 
        end; 
      end; 
    end; 
  end; 
end; 请问这里的time的interval是多少,还有 Timer2.Enabled := true; Timer3.Enabled := true;这里的time2,time3 起什么作用,还有,还有如何捕捉到异常再去执行procedure TForm2.Timer4Timer(Sender: TObject); 
  try 
  //...正常代码 
  except 
    on E:Exception do 
    begin 
      if Pos('连接失败',E.Message) > 0 then 
        ADOConn.Close; //关闭连接  //这里去执行这个time事件吗 
    end; 
  end;(* 这个事件,这个处理过程也会关闭ADOConnection1,如何没有保存的数据就没有了,能不能实现如果没有连接成功就会延迟10秒再连后如果成功再保存 

解决方案 »

  1.   

    数据库重连基本原理: 
    目前我们主要使用TNewAdoCommand执行sql语句,TAdoConnection作为connection连接数据库. 
    TNewAdoCommand封装了TAdoCommand对象,通过NEWExecute调用过程Execute,一旦执行失败, 
    Execute会抛出异常,通过捕捉异常可以获得异常信息,从异常信息里判断是语句的语法错误还是 
    连接错误信息,因此我们只需要更改NewExecute就可以达到我们的目的。如下是具体的修改代码 
      A.需要在主线程的FormCreate和start时对 sReconnectConfig (需要重连的关键字)进行初始化,sReconnectConfig在define中定义,为全局变量 
      //20090311 zhuzc add for 数据库自动重连,数据库自动连接的时间间隔 
        dtConnectDelayTime := 1; 
        dtLastConnectTime := Now; 
       sReconnectConfigFile :=  extractFilePath(Application.ExeName); 
       if  sReconnectConfigFile[length(sReconnectConfigFile)] <> '\' then 
           sReconnectConfigFile := sReconnectConfigFile + '\'; 
       sReconnectConfigFile := sReconnectConfigFile + 'config.ini'; 
      if not FileExists(sReconnectConfigFile) then 
      begin 
        sMsg := '警告:不存在配置文件' + sReconnectConfigFile + ' - reconnection,将无法实现重连数据库功能'; 
        showErrorMsg(sMsg,sMsg); 
      end; 
      if  FileExists(sReconnectConfigFile) then 
        LoadReconnectConfig(sReconnectConfigFile,sReconnectconfig); 
         
         
    B.在common中定义过程 LoadReconnectConfig 和 stringlistpos ,用于重连事件的文件加载及事件匹配,见common.pas C.重连函数如下 

      1.执行出现错误,识别错误为连接问题,这个通过stringlistpos函数来实现,连接问题的事件通过sReconnectConfig来获取 
      2.检查是否到下次连接时间,没有则退出,必须考虑频繁重新连接的问题. 
      3.重连 
      4.重连成功,dtLastConnectTime:= now,dtConnectDelayTime:=1; 这时候需要恢复重连时间为1 
      5.重连不成功; dtLastConnectTime := now;dtConnectDelayTime := dtConnectDelayTime * 2;if dtConnectDelayTime >= 60 then dtConnectDelayTime:= 60; 

    Sql版本: 
    function TNEWADOCommand.NEWExecute: _Recordset; 
    var 
      sError: string; 
      i: integer; 
    begin 
      //20090218 zhuzc add for 数据库断开自动重连 
      try 
        Result := Execute; 
      except 
        on E:exception do 
        begin 
          sError := E.message; 
          {if (pos('连接失败',sError) > 0) 
              or 
              (pos('不存在或拒绝访问',sError) > 0) 
              or 
              (pos('未指定的错误',sError) > 0) 
              or 
               (pos('Connection is busy with results for another  ',sError) > 0)  then } 
          if stringlistpos(sReconnectConfig,sError) > 0 then 
          begin 
            if now >= dtLastConnectTime + dtConnectDelayTime/60.0/60.0/24.0 then 
            begin 
              dtLastConnectTime := now; 
              Connection.Close; 
              try 
                Connection.Open; 
                dtConnectDelayTime:=1; 
                sError := sError + ',数据库重连成功'; 
              except 
                on E1:exception do 
                begin 
                  dtConnectDelayTime := dtConnectDelayTime * 2; 
                  if dtConnectDelayTime >= 60 then 
                     dtConnectDelayTime := 60; 
                 // dtConnectDelayTime := 1; 
                  sError := sError + ',再次重连数据库失败:' + E1.message + ',下次重连延时:' + IntToStr(dtConnectDelayTime) + '秒'; 
                end; 
              end; 
            end; 
          end; 
          raise Exception.Create(sError); 
        end; 
      end; 
      if Connection.Errors.Count > 0 then 
      begin 
        for i := 0 to Connection.Errors.Count - 1 do 
          sError := sError + Connection.Errors.Description; 
        raise Exception.Create(sError); 
      end; 
    end; 
    这个行不
      

  2.   

    这种方式不太好,你只是简单的查询,那么或许还可以,但是如果是提交数据,比如:Dbgrid中修改记录,提交的时候断线重连,那么就实现不了了。因为一旦连接关闭,Dataset全部被关闭。不过RemoteAdo已经内部解决这些问题。http://sites.google.com/site/remoteado/download
      

  3.   

    RemoteAdo能应用在我的delphi数据库中吗,还有能不能设计超时时间长时timeout,也就是当断线到重新连接比如为20秒,是不是也能缓解一下问题
      

  4.   

    Timer2,Timer3是我自己系统的业务逻辑,你可以不用考虑,pingserver函数我已贴到原贴中
      

  5.   

    你只要这样看就可以了:
    procedure TForm2.Timer4Timer(Sender: TObject); 
    var 
      strError:string; 
      ConnStr,ServerIp:string; 
      tmpStrList :TStringList; 
    Const 
      CONNECTABORT_SQLSERVER1 = '08S0 '; //连接失败的错误号(SQLSERVER) 在简体版本下,显示不出最后一位 
      CONNECTABORT_SQLSERVER2 = '08S01'; //连接失败的错误号(SQLSERVER) 
      CONNECTFAULT_SQLSERVER = '08001'; //连接不上服务器的的错误号(SQLSERVER) 
    begin 
      if Form1.ADOConnection1.Errors.Count >0 then 
      begin 
        strError := Form1.ADOConnection1.Errors.Item[0].SQLState; 
        if (strError = CONNECTABORT_SQLSERVER1)or(strError = CONNECTABORT_SQLSERVER2)or(strError = CONNECTFAULT_SQLSERVER) then 
        begin 
          ConnStr := Form1.ADOConnection1.ConnectionString; //获得数据库所在服务器的IP地址
          tmpStrList := Common.SplitString(ConnStr,';');    //获得数据库所在服务器的IP地址
          ServerIp := tmpStrList.Values['Data Source'];     //获得数据库所在服务器的IP地址
          tmpStrList.Free;                                  //获得数据库所在服务器的IP地址      if PingServer(ServerIp) then 
          begin 
            Form1.ADOConnection1.Connected := false; 
            Try 
              Form1.ADOConnection1.Open; 
            Except 
            end; 
          end; 
        end; 
      end; 
    end; 
      

  6.   

    我试了,你这个还是每2秒去检测一下和服务器是否连接正常,连接不正常的话就关闭再重新连接,而不需要在每个窗体执行代码中连接异常时再执行这个time4timer事件,但这样会带来一个问题,如果我正在保存数据时断线了,你这事件就会关闭,数据就无法保存了
    ADOQUERY1.Connection:=nil;         
        try   
          adoConnection1.Close;   
          adoConnection1.Open;   
          ADOQUERY1.Connection:=adoConnection1;   
          ADOQUERY1.UpdateBatch();   
        except   
          showMessage(GetErrorInfo);   //提示出错信息   
        end;不知道这种方法能不能保存数据,我试试
      

  7.   

    还有可不可以利用adoConnection1或者ADOQUERY1的timeout事件设置使重连时间再延长些,比如有时断了8秒,我只要延时10,是不是就能解决了
      

  8.   

    首先,我介绍一下我的系统的数据库连接架构,整个系统中只有Form1中有一个AdoConnection,其他窗体如要连接数据库,都使用这个AdoConnection,并且该AdoConnection的KeepConnection属性为True,Timer4的功能就是检测这个AdoConnection有没有因为网络问题而断开连接,如果已断开连接,则尝试ping一下数据库服务器,如果能够ping通,则重连AdoConnection,否则什么也不做.
    如果你在保存数据时断线了,那么无论有没有写我这段检测代码,你都是无法成功保存数据的.但是如果没有这段检测代码,那么你这个AdoConnection的Connectioned属性就永远为true了(事实上,他已断开),除非你重起你的程序,加了我这断代码后,就能检测到AdoConnection的假连接状态,并恢复正常!我认为已经很明白了,不知道你还有什么疑问呢?
      

  9.   

    adoConnection自身无法检测网络故障,即使网络已断了好久好久,他的Connectioned也还是True,也不会自动重连.
      

  10.   

    ADOQUERY1.Connection:=nil;        
        try  
          adoConnection1.Close;  
          adoConnection1.Open;  
          ADOQUERY1.Connection:=adoConnection1;  
          ADOQUERY1.UpdateBatch();  
        except  
          showMessage(GetErrorInfo);  //提示出错信息  
        end; 
    用这种方法解决不少问题
    现在最后有个问题,如果保存时网断还是会提示一般网络问题,请查看文档,能不能提示,网络连接失败,请稍后
      

  11.   

    在每个AdoQuery的执行代码里加上TRY结构,肯定可以屏蔽缺省的错误提示消息的
      

  12.   

    还有你这个方法非常不效率,每次查询数据库都要重连一次,完全没必要,还不如这样:
        try  
          ADOQUERY1.Connection:=adoConnection1;  
          ADOQUERY1.UpdateBatch();  
        except  
          showMessage(GetErrorInfo);  //提示出错信息  
        end; 
    网络通自然执行成功,不通的话,再怎么重连还是不成功,而且还会产生尝试连接数据库的延时
      

  13.   


    你说的很对,所以我每次还是ping一样网络,如果成功就不必要,如果不成功就再执行以上代码我试了网络断开了,你用try也不行,还是提示一般性网络问题,我试了,