开发了一个数据备份服务,希望每天自动执行数据备份。
思路:做了个死循环,判断日期是否大于9999-12-31。
子循环判断每天是否做过备份,做过了就不执行。
里面还有子个循环判断是否到备份时间,如果是则开始备份,否在不备份。
服务开发完了,竟在服务启动的时候判断时间做备份,第二天却并没用自动备份。
如果手动重启服务,又会做备份。会是哪的问题啊? 
我把代码用程序断点执行,会一直死循环。我在服务创建时创建了个线程,线程执行备份操作。
按道理讲服务没停止,线程应该一直执行,即第二天也应该自动备份啊。
即使电脑重启,服务是自动启动的,也不应该会造成不备份的情况啊。
求指点!!!

解决方案 »

  1.   

    是哪种数据库呢?MSSQL、MYSQL都有可以自动备份的功能。MSSQL通过JOB可以实现
    MYSQL也可以通过设置自动备份的时间来实现。至于从数据库自动备份出来后,如果想再做个异机备份,那么写个bat批处理,通过XP的任务计划即可很方便的实现。
      

  2.   

    sybase数据库,MSSQL和MYSQL都可以自动备份。
    我就是不想用批处理,应为批处理要在DOS界面里显示数据库密码不安全。
    而且一旦有修改发布很麻烦,我有100多台服务器需要自动备份,未来会有超过300台。
    所以想设计个服务自动备份,而且程序是调用的存储过程执行备份,如果有变动,
    我直接修改下存储过程就下发下可以了。现在的问题就是服务仅在启动的时候执行,
    而没有在第二天合适的时间执行,把服务重新启动又可以了,会是哪写错了?
      

  3.   

    参考一下  CreateWaitableTimer 这个函数的功能
      

  4.   

    TO楼上的热心同学我也很想用批处理,只是批处理可以右键编写,不安全。
    SYBASE管理器没有备份功能,只有备份命令可以使用。
    考虑到实际情况,每个服务器的备份路径、时间、方式都可能不同。
    我现在备份方式采用数据表管理,方便个性化管理。备份用存储过程执行,
    期间从表中读取备份方式,所有没采用批处理。
      

  5.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
      DB, CTMemDataSet, CTDataSet, CTQuery,DateUtils, CTLibDatabase,
      CTStoredProc,WinSock,StrUtils;type
      Tdbbak = class(TService)
        CTLibDatabase1: TCTLibDatabase;
        CTQuery1: TCTQuery;
        CTStoredProc1: TCTStoredProc;
        procedure ServiceStart(Sender: TService; var Started: Boolean);
        procedure ServiceStop(Sender: TService; var Stopped: Boolean);
        procedure ServicePause(Sender: TService; var Paused: Boolean);
        procedure ServiceContinue(Sender: TService; var Continued: Boolean);
      private
        { Private declarations }
      public
        function GetServiceController: TServiceController; override;
        { Public declarations }
      end;
      NetThread = class(TThread)
      protected
         procedure Execute; override;
      end;
    var
      dbbak: Tdbbak;implementation
    var
       NetThread1 : NetThread;{$R *.DFM}procedure ServiceController(CtrlCode: DWord); stdcall;
    begin
      dbbak.Controller(CtrlCode);
    end;function Tdbbak.GetServiceController: TServiceController;
    begin
      Result := ServiceController;
    end;function ComputerName:string;
    var
    FStr:PChar;
    FSize:Cardinal;
    begin
       FSize:=255;
       GetMem(FStr,FSize);
       Windows.GetComputerName(FStr,FSize);
       Result:=FStr;
       FreeMem(FStr);end;
    procedure Tdbbak.ServiceStart(Sender: TService; var Started: Boolean);
    begin
       NetThread1 := NetThread.Create(false);
       Started:=True;
    end;procedure NetThread.Execute;
    var
      oldtime,subtime,H,M,i,backupsum,backupsumnow:integer;
      closedtime,dobacktime:string;
      sr: TSearchRec;    //定义 TSearchRec 结构变量
      Attr: Integer;     //文件属性
      s: string;         //要搜索的内容
      ListName,ListTime: TStringList; //存放搜索结果
      FileName: string;
      ti: Integer;
      dt: TDateTime;
      j:integer;
      FileTimeMin:Double;
      MinL:integer;//最小日期序号
    begin
        dbbak.CTLibDatabase1.ServerName:= ComputerName;
        dbbak.CTLibDatabase1.DbName:='SCS';
        dbbak.CTLibDatabase1.UserName:='sa';
        dbbak.CTLibDatabase1.Password:='sk30673';
        dbbak.CTLibDatabase1.Connected:=false;
        dbbak.CTLibDatabase1.Connected:=true;
        while  (now()-strtodatetime('9999-12-31'))<0 do
        begin
        //判断今日是否备份
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select BKEndTime from DBBackupLog where  BKEndTime = (select max(BKEndTime) from DBBackupLog where BKStatus = '''+'2'+''') ');
        dbbak.CTQuery1.Open;
        if  formatdatetime('yyyy-mm-dd',dbbak.CTQuery1.fieldbyname('BKEndTime').AsDateTime) <> formatdatetime('yyyy-mm-dd',now) then
        i:=0
        else
        i:=1;
        dbbak.CTLibDatabase1.Connected:=false;    if i=0 then   //i=0时今日未备份执行
        begin
        dbbak.CTLibDatabase1.Connected:=false;
        dbbak.CTLibDatabase1.Connected:=true;
        //取出历时最长备份时间
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'BackupMAXTime'+''' ');
        dbbak.CTQuery1.Open;
        oldtime:=strtoint(dbbak.CTQuery1.fieldbyname('RegValue').AsString);
        //取出备份时间提前量
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'BackupAdvanceTime'+''' ');
        dbbak.CTQuery1.Open;
        subtime:=strtoint(dbbak.CTQuery1.fieldbyname('RegValue').AsString);
        //取得关店时间
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'StoreClosedTime'+''' ');
        dbbak.CTQuery1.Open;
        closedtime:=trim(dbbak.CTQuery1.fieldbyname('RegValue').AsString);
        //算出备份时间点 。关店时间-历时最长备份时间-备份时间提前量
        dbbak.CTLibDatabase1.Connected:=false;
        H:=(strtoint(LeftStr(closedtime,2))*60+strtoint(copy(closedtime,4,2))-oldtime-subtime) div 60; //算出备份小时
        M:=(strtoint(LeftStr(closedtime,2))*60+strtoint(copy(closedtime,4,2))-oldtime-subtime) mod 60; //算出备份分钟
        dobacktime:=datetimetostr(dateof(now()))+' '+inttostr(h)+':'+inttostr(m)+':'+'00';    //查询现有备份数量
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'BackupSumNow'+''' ');
        dbbak.CTQuery1.Open;
        backupsumnow:=strtoint(trim(dbbak.CTQuery1.fieldbyname('RegValue').AsString));    //查询最大备份数量
        dbbak.CTQuery1.Close;
        dbbak.CTQuery1.ClearSQL;
        dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'BackupSum'+''' ');
        dbbak.CTQuery1.Open;
        backupsum:=strtoint(trim(dbbak.CTQuery1.fieldbyname('RegValue').AsString));    dbbak.CTLibDatabase1.Connected:=false;    //当系统时间到开始执行备份
        while  (now()-strtodatetime(dobacktime))>0 do
        begin
           dbbak.CTLibDatabase1.Connected:=false;
           dbbak.CTLibDatabase1.Connected:=true;
           dbbak.CTStoredProc1.ExecProc;
           dbbak.CTLibDatabase1.Connected:=false;
           if backupsumnow = backupsum  then  //当现有备份数量等于最大备份数量
           begin
           //查询备份路径
           dbbak.CTLibDatabase1.Connected:=false;
           dbbak.CTLibDatabase1.Connected:=true;
           dbbak.CTQuery1.Close;
           dbbak.CTQuery1.ClearSQL;
           dbbak.CTQuery1.SQL.Add('select RegValue from Registry_SKYL where RegName = '''+'BackupPath'+''' ');
           dbbak.CTQuery1.Open;
           s:=trim(dbbak.CTQuery1.fieldbyname('RegValue').AsString)+'SCS*.dmp';       Attr := faAnyFile;             //文件属性值faAnyFile表示是所有文件
           ListName := TStringList.Create;  //文件名称List建立
           ListTime := TStringList.Create;  //文件修改时间 List建立
           if FindFirst(s,Attr,sr)=0 then //开始搜索,并给 sr 赋予信息, 返回0表示找到第一个
           begin
              repeat                       //如果有第一个就继续找          FileName:=trim(dbbak.CTQuery1.fieldbyname('RegValue').AsString)+sr.Name;
              ListName.Add(FileName);         //用ListName记下结果
              ti := FileAge(FileName);
              dt := FileDateToDateTime(ti); //转换
              ListTime.Add(DateTimeToStr(dt));         //用ListTime记下结果
              until(FindNext(sr)<>0);      //因为sr已经有了搜索信息, FindNext只要这一个参数, 返回0表示找到
           end;
           FindClose(sr);                 //需要结束搜索, 搜索是内含句柄的
           FileTimeMin:=strtodatetime('9999-12-31');
           MinL:=0;
           for j:=0 to (ListTime.Count-1)   do
           begin
              if  (strtodatetime(ListTime.Strings[j])-FileTimeMin)<0  then
              begin
              FileTimeMin:=strtodatetime(ListTime.Strings[j]);
              MinL:=j;
              end;
           end;
           //删除最旧备份SCS
           if   FileExists(ListName.Strings[MinL])   then
           DeleteFile(ListName.Strings[MinL]);
           //删除最旧备份master
           if   FileExists(StringReplace(ListName.Strings[MinL],'SCS','master',[rfReplaceAll]))  then  //替换文件名SCS为master
           DeleteFile(StringReplace(ListName.Strings[MinL],'SCS','master',[rfReplaceAll]));
           //释放内存
           ListTime.Free;
           ListName.Free;
           break;
           end
           else
           begin
           // 更新现有备份数量统计
           backupsumnow:=backupsumnow+1;
           dbbak.CTQuery1.Close;
           dbbak.CTQuery1.ClearSQL;
           dbbak.CTQuery1.SQL.Add('update Registry_SKYL  set RegValue = '''+inttostr(backupsumnow)+'''  where RegName = '''+'BackupSumNow'+'''  ');
           dbbak.CTQuery1.ExecSQL;
           break;
           end;
        end;
        end;
        end;
        end;procedure Tdbbak.ServiceStop(Sender: TService; var Stopped: Boolean);
    begin
       NetThread1.Terminate;
       Stopped:=True;
    end;procedure Tdbbak.ServicePause(Sender: TService; var Paused: Boolean);
    begin
        NetThread1.Suspend;
        Paused:=True;
    end;procedure Tdbbak.ServiceContinue(Sender: TService; var Continued: Boolean);
    begin
        NetThread1.Resume;
        Continued := True;
    end;end.
      

  6.   

    加个Tdbbak.ServiceExecute(Sender:TService);  //定义
    procedure Tdbbak.ServiceExecute(Sender:TService); 
    begin
        while not Terminated do begin
             Sleep(10);
             ServiceThread.ProcessRequests(false);
        end;
    end;
    一般是这样:
      while True do
      begin
           if 当前时间=定义的时间 then
                   执行备份
      end;建议楼主先做个测试:
    例:通过服务在指定的时间去复制某个目录下的文件,成功后,再加入数据库中的内容。
      

  7.   

    我的思路和你下面写的一样 
    只是你上面的代码如果运行不是一直sleep一直不响应???
    因为我没有关闭服务啊
      

  8.   


    while  (now()-strtodatetime('9999-12-31'))<0 do
    ......
       while  (now()-strtodatetime(dobacktime))>0 do
           ......你可以在这两个循环中做个调试,输出到Tmemo或 日志中去,看看是不是某个控制没有考虑周到
    例如dobacktime是否每次都能正确地取到
      

  9.   

    循环是执行了,现在服务又出现自动停止的情况了。
    测试代码如下:
    procedure TService1.ServiceExecute(Sender: TService);
    begin
         while not Terminated do
         begin
            if strtoint(rightstr(floattostr(now),5)) mod 2 = 0 then
            begin
               CTLibDatabase1.Connected:=false;
               CTLibDatabase1.Connected:=true;
               CTQuery1.Close;
               CTQuery1.ClearSQL;
               CTQuery1.AddSQL('insert into test2011 (demo) values ('''+'1'+''') ');
               CTQuery1.ExecSQL;
            end;
            ServiceThread.ProcessRequests(false);
         end;
    end;服务大概运行了4分钟自动停止了,这是什么原因造成的?我需要服务一直运行啊~!!!
      

  10.   

    我建议你先把有关数据库方面的内容去掉,先把这个服务调试正确后,再加入数据库方面的业务逻辑。
    逐步调试,看看问题出在哪一个环节。上面两个循环,分别输出调试内容,看在哪个循环中出现了中断服务的情况。直接输出到Tmemo中,不用数据库,比较直观和 容易一些。
      

  11.   

    而且,你频繁地使用       
    CTLibDatabase1.Connected:=false;
    CTLibDatabase1.Connected:=true;
    也不可能是出现异常的原因之一。再说,即使用了数据库,也只是在满足条件时,才去连接数据库,用完了断开,而不是在循环中一直去尝试连接。毕竟一天中,只有一个时间是满足你去执行备份的,其他时间都不要去与数据库打交道。
      

  12.   

    找到问题的原因了是我的代码的问题。
    不连数据库没问题,连数据库的话在执行一段时间后会报下面的错误Service failed on execute: CTLibDatabase1: Message  : 84083972
    Severity : 5
    ct_connect(): network packet layer: internal net library error: Net-Lib protocol driver call to connect two endpoints failed
    Failed to connect to the server - Error is 0 操作成功完成。数据库连接失败。之前成功写入3984次后面就不行了,数据库连接不稳定???
      

  13.   

    我加了个try except 解决了,的确是很有必要把代码优化下了,非常感谢tgbd的帮助。