===============================
解决方法一:异常时关闭连接,WinXP,win7 32位大部分情况都是起作用的,不过在有些windows操作系统下(如家庭版)不起作用,不知为何?
===============================
try
//执行sql操作
except
AdoConnection.close;//出现异常时关闭连接,在执行sql语句时会自动打开连接,从而实现断线重连
end;
===============================
解决方法二:ADO控件动态创建,独立设置连接字符串,为了避免连接不上时界面卡死,可以考虑放到线程中执行。
推荐,亲测有效
===============================
unit untMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, IniFiles, ExtCtrls, DB, ADODB,ActiveX; type TFrmMain = class(TForm) Timer2: TTimer; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormShow(Sender: TObject); procedure Timer2Timer(Sender: TObject); private { Private declarations } public { Public declarations } procedure getXXData(); end; //ADO连接获取数据线程 TAdoThread = class(TThread) protected procedure execute; override; end; var FrmMain: TFrmMain; ConString: string; { 初始化临界区CS变量 } CS: TRTLCriticalSection; implementation uses untabout; {$R *.dfm} { TForm1 }{ 写程序异常日志 } procedure write_error_log(str: string); var F: TextFile; mfile: string; begin try //判断保存日志文件的目录是否存在 if not DirectoryExists(ExtractFilePath(ParamStr(0)) + 'log') then MkDir(ExtractFilePath(ParamStr(0)) + 'log'); //按日期及时间设定保存日志的文件名 mfile := ExtractFilePath(ParamStr(0)) + 'logErrLog_' + formatdatetime('yyyy-mm-dd', now) + '.txt'; AssignFile(F,mfile); if not FileExists(mfile) then Rewrite(F);//如果文件不存在,则创建一个新的文件,并写入 Append(F); //追加写入 Writeln(F,str);//写入并换行 CloseFile(F); except end; end; procedure TFrmMain.FormClose(Sender: TObject; var Action: TCloseAction); begin { 清除线程CS变量 } DeleteCriticalSection(CS); Timer2.Enabled := False; end; procedure TFrmMain.FormShow(Sender: TObject); var clientini: TIniFile; db_server,user,password:string; begin { 获取ini配置信息} clientini := TIniFile.Create('.config.ini'); try if clientini<>nil then begin db_server := trim(clientini.readString('database','db_server','')); user := trim(clientini.readString('database','user','sa')); password := trim(clientini.readString('database','password','')); ConString := 'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=' +user+';Password='+password+';Initial Catalog=Testdb;Data Source='+db_server; end; finally clientini.Free; end; InitializeCriticalSection(CS);//初始化线程临界区 end; procedure TFrmMain.Timer2Timer(Sender: TObject); begin Timer2.Enabled := False; TAdoThread.Create(False); end; procedure TFrmMain.getXXData(); var ADOStoredProc1: TADOStoredProc; begin ADOStoredProc1 := TADOStoredProc.Create(nil);//动态创建ADO控件 try try ADOStoredProc1.ConnectionString := ConString;//采用独立的连接字符串 if ADOStoredProc1.Active then ADOStoredProc1.Active := false; ADOStoredProc1.ProcedureName := 'GetData'; ADOStoredProc1.Prepared := false; ADOStoredProc1.Parameters.Refresh; ADOStoredProc1.Prepared := true; ADOStoredProc1.ExecProc; except on E:Exception do begin write_error_log(FormatDateTime('yyyy-mm-dd hh:nn:ss',Now) + '>> 执行getXXData时发生异常!错误原因:'+E.Message ); end; end finally ADOStoredProc1.Free; end; end; { TAdoThread } procedure TAdoThread.execute; begin inherited; FreeOnTerminate := True; //设置线程执行完成后自动释放 {进入线程临界区} EnterCriticalSection(CS); try CoInitialize(nil); //线程中使用ADO,必须调用(需Uses ActiveX) {读取HIS数据} FrmMain.getHisData(FrmMain.hasCharge); CoUninitialize; finally { 离开线程临界区 } LeaveCriticalSection(CS); end; FrmMain.Timer2.Enabled := True; end; end. ============================ 其他解决方法:未验证,资料来自: http://bbs.csdn.net/topics/390958648 ============================ Win7上ADO连接SQLServer过几十分钟后自动断网(被防火墙拦截等)问题终于解决了,困惑了很久 今天终于解决了!方法很简单,和大家共享一下。 问题现象:ADO连接SQLServer过几十分钟后(有的过几周)数据库连接无缘无故断开, 再做数据库操作报错“连接失败”。实际上此时数据库服务器可以ping通, 新创建其他ADO控件连接数据库也没问题。就这个ADO不行了。 问题分析: 刚开始想得比较简单,只要创建个线程或者Timer时时判断ADOConnecton1.Active属性=false不得了么。但实际上因为后台原因 或者服务断开再重连、被防火墙拦截等意外情况发生时ADOConnecton1.Active属性仍然是true!无法判断。 后来想到用ping,如果ping不通那就断开了?!但是ping通了未必说明数据库就能连通!ping无法判断数据库能否连通。 那么线程里面不断执行个select GetDate 之类简单SQL,如果失败就判断数据库断开行不行呢?显然不行, 多用户同时不断连接数据库对服务器压力太大了,不可取。 后来网上查了很多材料,有人提出捕获OleException的方法,既不创建线程和定时器判断数据库是否断开,而是当用户执行操作 发生Ole异常时捕获它,如果是数据库连接错误,那么恢复数据库连接即可,我在他们代码基础上完善了一下,以下是实现代码。 控件: Button1: TButton; ADOConnection1: TADOConnection; Button2: TButton; ADOQuery1: TADOQuery; DataSource1: TDataSource; DBGrid1: TDBGrid; ApplicationEvents1: TApplicationEvents; 代码: uses ComObj; {$R *.dfm} procedure TForm1.ApplicationEvents1Exception(Sender: TObject; E: Exception); var I: integer; begin //请执行如下命令或者其他方法强制产生数据库连接断开情况,以触发如下异常。 //net stop MsSqlServer //net start MsSqlServer if (E is EOleException) and ((E as EOleException).ErrorCode= -2147467259) then begin ADOConnection1.Connected := False; try ADOConnection1.Connected := True; except On E2: Exception do begin MessageDlg('重连数据库发生错误:'#13 + E2.Message, mtError, [mbOK], 0); end; end; end; end; procedure TForm1.Button1Click(Sender: TObject); var sSQL: string; begin sSQL:= 'Provider=SQLOLEDB.1;Password=YourPassword;Persist Security Info=True;' + 'User ID=sa;Initial Catalog=YourDatabase;Data Source=.'; with ADOConnection1 do begin LoginPrompt:= false; Connected:= false; ConnectionString:= sSQL; Connected:= true; end; ShowMessage('ok'); end; procedure TForm1.Button2Click(Sender: TObject); begin with ADOQuery1 do begin Close; SQL.Clear; SQL.Add('select * from Test'); Open; end; end;