数据库 远程备份和恢复

 

在论坛混了这么多年, 看到的一个很明显的趋势是, 用VFP和SQL SERVER来做系统的网友越来越多。怎么从VFP里来操作或者管理SQL SERVER也成为很多人关心的问题。 对SQL SERVER的数据操作,可以用视图,SPT或者ADO来做,但对服务器本身的管理,似乎只有用SPT来发送一些命令了。其实, 微软为客户端操作SQL SERVER开发了一套完整的工具, 这就是SQL - DMO (Distributed Management Objects). 这是一套COM组件,可以在各种语言里使用, VFP里自然也可以用了。
我准备花点时间,写些这方面的介绍文章,然后做个实例,算是我通过MCDBA后,给大家的礼物吧。下面的介绍和例子,是针对SQL SERVER 2000和VFP7的。

一. 用SQL -DMO的必要性

大部分VFPER开发的程序,都是中小规模的系统,因为这是VFP最适用的范围。而这样的系统,很多情况下是,客户端没有专业IT人士维护,更不要说专门的DBA了。对于使用SQL SERVER的系统,就带来了一些问题。 SQL SERVER是一套比较大的数据库专业软件, 是经常需要维护和清理的,而我们这些系统开发者, 总不能老跑去用户那里做维护工作吧,尤其对商业软件来说,这是很大的成本了。如果可以把对SQL SERVER的维护工作放到自己的程序里,甚至把SQL SERVER的安装无缝并入到自己的程序的安装包里,相信大家都会很乐意的。 DMO的功能就能满足我们的这些需要。通过它,可以从程序里用命令方式来操作SQL SERVER:停止/启动服务,建立数据库和表,添加用户和权限,备份/恢复数据库,数据导入/导出/发布...  DMO的作用就是把我们能在Enterprise Manager里完成的功能,完全用代码来做.

二. 微软的桌面数据引擎 (Desktop Database Engine)

我们都知道SQL SERVER 2000有四个版本: 个人版,开发者版,标准班和企业版. 其实,还有一个版本,就是桌面数据引擎(DDE)。 DDE几乎具有
SQL SERVER标准版和企业版的所有功能,不能支持的只是少数几个不常用的功能。而它和其它版本的区别是, DDE没有任何图形管理界面,没有ENTERPRISE MANAGER,没有查询分析器等等工具。 对它的管理,主要是通过DMO或者专门的API来进行,它的另一个优点是, 提供了安装程序,可以直接加到第3方软件里进行安装。每个版本的SQL SERVER CD里都带有DDE, 在MSDE目录下,运行SETUP程序就可以安装。至于怎么把它加到自己的程序里安装,大家查一下SQL SERVER的帮助文件就可以找到。
DDE的限制是: 只适宜中小型系统(比如没有5个以上的用户同时连接和运行大型SQL命令), 如果同时访问的用户很多, DDE就会比正常的SQL SERVER慢了。

这样, DDE+DMO就可以实现我们上面所要求的功能了。这种做法甚至可以不让用户知道你是在使用SQL SERVER做为数据库。当然, DMO不是只能操作DDE,它可以操作所有版本的SQL SERVER。

三. DMO的安装

其实DMO主要就是一个DLL文件而已: SQLDMO.DLL。具体位置在C:/Program Files/Microsoft SQL Server/80/Tools/Binn目录里, 在同一目录里还有个帮助文件Sqldmo80.hlp. 如果你在程序里不能使用DMO, 找到这个DLL文件,注册一下,就可以了。另外在C:/Program Files/Microsoft SQL Server/80/Tools/ Devtools/Samples/Sqldmo 目录下,有SQLDMO的例子,但都是VB和VC++的。VB的例子和VFP很接近的.


四. 初步接触DMO

在这里写几个简单的句子,来看看DMO的强大. 这些命令可以直接在命令窗口里一行一行测试, 只是用它们来显示数据库的信息。至于添加数据库,数据表,备份和恢复等比较复杂的功能,得在实例里做。

oServer=CreateObject("SQLDMO.SQLServer") &&建立SERVER对象
oServer.Connect("Snoopy","sa","778899") &&连接到你的服务器
? oServer.Databases.Count  &&显示服务器上的数据库总数
? oServer.Databases.Item(1).Name  &&显示第一个数据库的名字

oDB=oServer.Databases("PUBS") &&建立数据库对象
? oDB.Tables.Count  &&显示库里表的数目
oTable=oDB.Tables("Titles")    &&建立表对象
? oTable.Rows  &&显示表里的记录数
? oTable.Columns.Count &&显示表的列数

**显示列的属性
? oTable.Columns(1).Name
? oTable.Columns(1).type
? oTable.Columns(1).Datatype
? oTable.Columns(1).Identity
? oTable.Columns(1).InPrimaryKey


例子:


Backup和Restore数据库


oServer=CreateObject("SQLDMO.SQLServer") &&建立SERVER对象
oServer.Connect("Snoopy","sa","778899") &&连接到你的服务器

**备份
oBackup=CreateObject("SQLDMO.Backup") &&建立备份对象
oBackup.Database="PUBS" &&指定备份数据库
oBackup.Password="8899" &&给备份文件加密码
oBackup.Files="D:/Temp/PUBBack.Dat" &&指定目标文件
oBackup.SQLBackup(oServer) &&运行备份命令,速度很快的

**备份恢复
oRestore=CreateObject("SQLDMO.Restore")
oRestore.Database="PUBS"
oRestore.Files="D:/Temp/PUBBack.Dat"
oRestore.SQLRestore
oRestore.SQLRestore(oServer) &&先试不加密码,备份失败
oRestore.Password="8899"
oRestore.SQLRestore(oServer)

SQL SERVER提供几种数据库备份方式,
一种是完整备份 (Full Backup), 第二种是差异备份(Differential Backup), 第三种是日志备份, 第四种是文件备份

完整备份是把整个数据库做个备份,差异备份只是备份进行了完整备份后数据库里的新变化。当数据库很大时, 完整备份很费空间和时间,可以根据情况定期做,比如每周或者每月做一次完整备份。 其它时间可以进行差异备份,比如每天一次,或者半天一次, 也可以结合进行日志备份。文件备份是直接备份数据库的数据和日志文件。和在操作系统里做备份一样.

在恢复的时候,只要先恢复完整备份,然后恢复最后一个差异备份就可以。如果有日志备份,还需要恢复差异备份后所做的日志备份。

备份种类通过 备份对象的Action属性来决定.
oBackup.Action=0 && 参数: 0 - 完整备份,1- 差异备份,  2- 文件备份, 3 -日志备份

 


Server对象的一些属性和方法

属性
AutoReConnect: 当连接断开,后是否自动重连
ConnectionID: 本连接的ID
HostName: 本地机器的名字
Isdbcreator, Isdiskadmin, Isprocessadmin, Issecurityadmin, Isserveradmin, Issetupadmin, Issysadmin: 返回当前连接用户是否属于某类SERVER ROLE,比如是不是SA

LoginTimeout: 决定连接超时时间,默认为60秒
SaLogin: 当前连接是不是SA
Status:服务器当前状态
 VersionMajor,VersionMinor: SQL SERVER的版本号

方法:

AttachDB, DetachDB: 添加或者剥离数据库
Connect, Disconnect, Close: 连接, 断开,或者关闭当前服务器对象(oServer)
VerifyConnection: 测试当前连接是否断开
Reconnect: 重新连接
Start, Stop, Shutdown: 用来启动,停止或者关闭服务器
BeginTransaction, RollbackTransaction, CommitTransaction: 操作事务
EnumServerAttributes: 返回服务器的大部分设置参数
EnumLocks: 返回服务器上所有的加锁进程
KillProcess: 强行中断一个进程

 

在VFP里来操作和管理SQL SERVER (2) (介绍SQL-DMO)
用DMO来建立任务,并让它定时运行. 执行环境必须是NT或者WINDOWS 2000, 因为需要运行SQL AGENT

***建立任务(JOB)
oJob=CreateObject("SQLDMO.Job") &&创建任务对象
ojob.Name="Pubs_Daily_Backup" &&任务名称
oServer.JobServer.Jobs.Add(oJob) &&加到SQL SERVER的任务里
oJob.BeginAlter &&开始定义任务
oJobStep=CreateObject("SQLDMO.JobStep") &&创建任务步骤对象
oJobStep.Name = "Step_1" &&步骤名称

oJobStep.StepID = 1 &&步骤号码
oJobStep.DatabaseName="Pubs" &&数据库名称
oJobStep.SubSystem= "TSQL" &&任务类型,可以是TSQL或者操作系统命令(CmdExec), 或者ActiveScripting

cFName="PubBack"+Dtoc(Date(),1)+".dat" &&备份目标文件名
oJobStep.Command ="Backup database Pubs to Disk='D:/Temp/"+cFname+"' With Password='7788'" &&执行备份的TSQL命令
oJobStep.OnFailAction = 2  && 如果任务失败退出。也可以设成发送EMAIL或者用NT里的NETSEND发信息
oJobStep.OnSuccessAction= 1  && 如果任务成功,退出。
oJob.JobSteps.Add(oJobStep) &&添加任务步骤
oJob.StartStepID = 1 &&从第一步开始执行,对多步骤的任务起作用
oJob.DoAlter &&保存修改

***把任务加到SCHEDULER里

oJobSchedule =CreateObject("SQLDMO.JobSchedule") &&创建Schedule对象
oJob = oServer.JobServer.Jobs("Pubs_Daily_Backup")&&创建任务对象
oJobSchedule.Name = "Daily_Execution" &&名称
oJobSchedule.Schedule.FrequencyType= 4  && 运行频率, 4是每日运行
oJobSchedule.Schedule.FrequencyInterval = 1 &&运行间隔, 1是每天
oJobSchedule.Schedule.ActiveStartDate =Dtoc(Date(),1) &&开始日期(今天), 必须是yyyymmdd格式
oJobSchedule.Schedule.ActiveStartTimeOfDay = "233000" &&开始时间(晚上11点30), 必须是 hhmmss格式
**下面2句设置是使任务永不过期
oJobSchedule.Schedule.ActiveEndDate=99991231  &&no end date
oJobSchedule.Schedule.ActiveEndTimeOfDay =235959 &&No end time

添加任务到SCHEDULE里
oJob.BeginAlter
oJob.JobSchedules.Add(oJobSchedule)
oJob.DoAlter


上述命令我在VFP7里都测试成功,在SQL SERVER里也看到了新添加的命令和运行设置,但因为我是用的WINDOWS ME,没法测试任务是否真的运行了。哪位有环境,可以帮我试试


下面这个帖子中的存储过程比较麻烦,不过调用起来比较简单。

------------------------------------------------

SQL SERVER2000数据库备份和恢复存储过程

 

我自己写的2个过程和一个函数,用于SQL SERVER2000数据库备份和恢复
拿出来和大家交流一下,过程和函数的详细说明在代码中
谢谢

 


/*备份数据库的过程*/
if exists(
select * from sysobjects
  where name='pr_backup_db' and xtype='p'
          )
begin
drop proc pr_backup_db
end
go

 

create proc pr_backup_db
@flag varchar(20) out,
@backup_db_name varchar(128),
@filename varchar(1000)  --路径+文件名字
as
declare @sql nvarchar(4000),@par nvarchar(1000)
if not exists(
select * from master..sysdatabases
  where name=@backup_db_name
  )
begin
select @flag='db not exist'  /*数据库不存在*/
return
end
else
begin
if right(@filename,1)<>'/' and charindex('/',@filename)<>0
begin
  select @par='@filename varchar(1000)'
  select @sql='BACKUP DATABASE '+@backup_db_name+' to disk=@filename with init'
  execute sp_executesql @sql,@par,@filename
  select @flag='ok'
  return
end
else
begin
  select @flag='file type error'  /*参数@filename输入格式错误*/
  return
end
end

 

GO

 

说明:pr_backup_db过程是备份你的数据库

 

 

/*创建函数,得到文件得路径*/
if exists(
select * from sysobjects
  where name='fn_GetFilePath' and xtype='fn'
        )
begin
drop function fn_GetFilePath
end
go

 

create function fn_GetFilePath(@filename nvarchar(260))
returns nvarchar(260)  
as
begin
declare @file_path nvarchar(260)
declare @filename_reverse nvarchar(260)
select @filename_reverse=reverse(@filename)
select @file_path=substring(@filename,1,len(@filename)+1-charindex('/',@filename_reverse))
return @file_path
end

 


GO

 


/*恢复数据库的过程*/
if exists(
select * from sysobjects
  where name='pr_restore_db' and xtype='p'
          )
begin
drop proc pr_restore_db
end
go

 

CREATE  proc pr_restore_db   
@flag varchar(20) out,    /*过程运行的状态标志,是输入参数*/     
@restore_db_name nvarchar(128),  /*要恢复的数据名字*/
@filename nvarchar(260)         /*备份文件存放的路径+备份文件名字*/
as
declare @proc_result tinyint  /*返回系统存储过程xp_cmdshell运行结果*/
declare @loop_time smallint  /*循环次数*/
declare @max_ids smallint    /*@tem表的ids列最大数*/
declare @file_bak_path nvarchar(260)  /*原数据库存放路径*/
declare @flag_file bit   /*文件存放标志*/
declare @master_path nvarchar(260)  /*数据库master文件路径*/
declare @sql nvarchar(4000),@par nvarchar(1000)
declare @sql_sub nvarchar(4000)
declare @sql_cmd nvarchar(100)
declare @sql_kill nvarchar(100)
/*
判断参数@filename文件格式合法性,以防止用户输入类似d: 或者 c:/a/ 等非法文件名
参数@filename里面必须有'/'并且不以'/'结尾
*/
if right(@filename,1)<>'/' and charindex('/',@filename)<>0
begin
select @sql_cmd='dir '+@filename
EXEC @proc_result = master..xp_cmdshell @sql_cmd,no_output
IF (@proc_result<>0)  /*系统存储过程xp_cmdshell返回代码值:0(成功)或1(失败)*/
begin
  select @flag='not exist'   /*备份文件不存在*/
  return  /*退出过程*/
end
/*创建临时表,保存由备份集内包含的数据库和日志文件列表组成的结果集*/
create table #tem(
     LogicalName nvarchar(128), /*文件的逻辑名称*/
     PhysicalName nvarchar(260) , /*文件的物理名称或操作系统名称*/
     Type char(1),  /*数据文件 (D) 或日志文件 (L)*/
     FileGroupName nvarchar(128), /*包含文件的文件组名称*/
     [Size] numeric(20,0),  /*当前大小(以字节为单位)*/
     [MaxSize] numeric(20,0)  /*允许的最大大小(以字节为单位)*/
   )
/*
创建表变量,表结构与临时表基本一样
就是多了两列,
列ids(自增编号列),
列file_path,存放文件的路径
*/
declare @tem table(      
     ids smallint identity,  /*自增编号列*/
     LogicalName nvarchar(128),
     PhysicalName nvarchar(260),
     File_path nvarchar(260),
     Type char(1), 
     FileGroupName nvarchar(128)
   )
insert into #tem
  execute('restore filelistonly from disk='''+@filename+'''')
/*将临时表导入表变量中,并且计算出相应得路径*/
insert into @tem(LogicalName,PhysicalName,File_path,Type,FileGroupName) 
  select LogicalName,PhysicalName,dbo.fn_GetFilePath(PhysicalName),Type,FileGroupName
   from #tem
if @@rowcount>0
begin
  drop table #tem
end
select @loop_time=1
select @max_ids=max(ids)  /*@tem表的ids列最大数*/
  from @tem
while @loop_time<=@max_ids
begin
  select @file_bak_path=file_path
   from @tem where ids=@loop_time
  select @sql_cmd='dir '+@file_bak_path
  EXEC @proc_result = master..xp_cmdshell @sql_cmd,no_output
  /*系统存储过程xp_cmdshell返回代码值:0(成功)或1(失败)*/
  IF (@proc_result<>0)
   select @loop_time=@loop_time+1 
  else
   BREAK /*没有找到备份前数据文件原有存放路径,退出循环*/
end
select @master_path=''
if @loop_time>@max_ids
  select @flag_file=1   /*备份前数据文件原有存放路径存在*/
else
begin
  select @flag_file=0  /*备份前数据文件原有存放路径不存在*/
  select @master_path=dbo.fn_GetFilePath(filename)
   from master..sysdatabases
   where name='master'
end
select @sql_sub=''
/*type='d'是数据文件,type='l'是日志文件 */
/*@flag_file=1时新的数据库文件还是存放在原来路径,否则存放路径和master数据库路径一样*/
select @sql_sub=@sql_sub+'move '''+LogicalName+''' to '''
   +case type
         when 'd' then case @flag_file
             when 1 then  File_path
      else @master_path
          end   
         when 'l' then case  @flag_file
      when 1 then  File_path
      else @master_path
          end   
   end
   +case type
    when 'd' then @restore_db_name
           +'_DATA'
           +convert(sysname,ids)  /*给文件编号*/
           +'.'
           +right(PhysicalName,3)  /*给文件加入后缀名,mdf or ndf*/
           +''',' 
    when 'l' then @restore_db_name
           +'_LOG'
           +convert(sysname,ids)   /*给文件编号*/
           +'.'
           +right(PhysicalName,3)  /*给文件加入后缀名,mdf or ndf*/
           +''',' 
    end
   from @tem
select @sql='RESTORE DATABASE @db_name FROM DISK=@filename with '
select @sql=@sql+@sql_sub+'replace'
select @par='@db_name nvarchar(128),@filename nvarchar(260)'
/*关闭相关进程,把相应进程状况导入临时表中*/
select identity(int,1,1) ids, spid
  into #temp
  from master..sysprocesses
  where dbid=db_id(@restore_db_name)
if @@rowcount>0 --找到相应进程
begin  
  select @max_ids=max(ids)
   from #temp
  select @loop_time=1
  while @loop_time<=@max_ids
  begin
   select @sql_kill='kill '+convert(nvarchar(20),spid)
    from #temp
    where ids=@loop_time
   execute sp_executesql @sql_kill
   select @loop_time=@loop_time+1
  end
end
drop table #temp
execute sp_executesql @sql,@par,@db_name=@restore_db_name,@filename=@filename
select @flag='ok'   /*操作成功*/
end
else
begin
SELECT @flag='file type error'  /*参数@filename输入格式错误*/
end

 


GO

 

 

 

 


--run

 

--备份数据库test_database
declare @fl varchar(10)
execute pr_backup_db @fl out,'test_database','c:/test_database.bak'
select @fl

 

--恢复数据库,输入的参数错误
declare @fl varchar(20)
exec pr_restore_db @fl out,'sa','c:/'
select @fl

 


--恢复数据库,即创建数据库test_database的复本test_db
declare @fl varchar(20)
exec pr_restore_db @fl out,'test_db','c:/test_database.bak'
select @fl

 


以上过程和函数在MS SQL2000运行成功,由于MS SQL7不支持用户自定义函数和表变量,要在MS SQL7下使用可以把函数fn_GetFilePath改写成过

 

程,把过程pr_restore_db中的表变量改写为临时表即可运行,有兴趣的朋友可以试试!


1.数据备份:
Close All
Clear
mypath_old=Sys(5)+Sys(2003)
mypath_new=Alltrim(Alltrim(mypath_old)+'/MYDBCBF')
If !Directory("&MYPATH_new.")
Md &mypath_new.
Endif
Set Default To &mypath_new.
mydbf_old=Getfile('bak','','',1,'请输入或选定备份文件名')
If Len(mydbf_old)=0
=Messagebox('你刚才没有录入任何文件名,备份没有成功!!',32,'提示信息')
Set Default To &mypath_old.
Else
mydbf_path=Left(mydbf_old,At('/',mydbf_old,Occurs('/',mydbf_old))-1)
If !Directory("&MYDBF_path.")
Md &mydbf_path.
ENDIF
ERASE &MYDBF_old.
handle=SQLExec(con,"backup database mydbc to disk=?MYDBF_old")
Set Default To &mypath_old.
If handle>0
=Messagebox('(^_^)数据成功备份到【 '+mydbf_path+' 】文件夹下!  ',64,'数据库备份')
Else
=Messagebox(Message(),16,'数据库备份')
Endif
Endif
二.恢复:
Close All
Clear
mypath_old=Sys(5)+Sys(2003)
mypath_new=Alltrim(Alltrim(mypath_old)+'/MYDBCBF')
Set Default To &mypath_new.
mydbf=Getfile('bak','','',1,'请选定要恢复的文件名')
Restore From mypath_old+'/myurl/url' Additive
sql_server=Alltrim(my_server)
sql_path=Alltrim(Right(sql_server,Len(sql_server)-Atc('/',sql_server)))
If Len(sql_path)=0
sql_restore_mdf='C:/Program Files/Microsoft SQL Server/MSSQL/Data/mydbc.MDF'
sql_restore_ldf='C:/Program Files/Microsoft SQL Server/MSSQL/Data/mydbc_log.ldf'
Else
sql_restore_mdf='C:/Program Files/Microsoft SQL Server/MSSQL$'+sql_path+'/Data/mydbc.MDF'
sql_restore_ldf='C:/Program Files/Microsoft SQL Server/MSSQL$'+sql_path+'/Data/mydbc_log.ldf'
Endif
*now_timer=1
Try
=SQLDisconnect(con)
Catch
Finally
Endtry
=SQLSetprop(0,"displogin",3)  &&永不显示信任连接提示
myurl="driver=sql server;server="+Alltrim(my_server)+;
";uid=sa;pwd="+Alltrim(my_pwd)+;
";database=MASTER"
con_master=Sqlstringconnect(myurl)
If con_master<0
=Messagebox('<@_@>本机已与服务器失去连接,您将退出本系统!',16,'系统信息')
Else
handle=SQLExec(con_master,"RESTORE DATABASE mydbc FROM DISK=?MYDBF With Replace;
    ,Move 'MYDBC_DATA' To ?SQL_RESTORE_mdf';
,Move 'MYDBC_LOG' To ?SQL_RESTORE_LDF'")
If handle>0
=MESSAGEBOX('^_^数据恢复成功!',32,'数据恢复')
Try
=SQLDisconnect(con_master)
Catch
Finally
Endtry
=SQLSetprop(0,"displogin",3)  &&永不显示信任连接提示
myurl="driver=sql server;server="+Alltrim(my_server)+;
";uid=sa;pwd="+Alltrim(my_pwd)+;
";database=mydbc"
con=Sqlstringconnect(myurl)
If con<0
=Messagebox('<@_@>本机已与服务器失去连接,您将退出本系统!',16,'系统信息')
Else
now_timer=0
Endif
Else
=Messagebox(Message(),16,'数据恢复')
Endif
Endif
Set Default To &mypath_old.

数据备份不用多作解释.对于数据恢复:
1.要注意在选定恢复文件时可能会改变当前路径.要在恢复数据后还原当前路径.
2.测试与数据源的连接.因为SQL2000的数据库MASTER等是自带的,只要测试能否连接上其中一个就行.
  因为在恢复时可能找不到你要恢复的自定义数据库,所以要测试SQL2000的数据表.
3.SQL2000的安装可能有自定义实例这个也要考虑.比方说你的服务实例名是SERVER那SQL2000生成的文件夹是:MSSQL$SERVER而不是MSSQL
4.在恢复数据时要断开与当前数据库的连接(与上面所述,用SQL2000的自带数据库作为当前连接),否则会产生异常.
5.数据恢复成功后,要恢复与自定义数据库的连接.

在论坛混了这么多年, 看到的一个很明显的趋势是, 用VFP和SQL SERVER来做系统的网友越来越多。怎么从VFP里来操作或者管理SQL SERVER也成为很多人关心的问题。 对SQL SERVER的数据操作,可以用视图,SPT或者ADO来做,但对服务器本身的管理,似乎只有用SPT来发送一些命令了。其实, 微软为客户端操作SQL SERVER开发了一套完整的工具, 这就是SQL - DMO (Distributed Management Objects). 这是一套COM组件,可以在各种语言里使用, VFP里自然也可以用了。
我准备花点时间,写些这方面的介绍文章,然后做个实例,算是我通过MCDBA后,给大家的礼物吧。下面的介绍和例子,是针对SQL SERVER 2000和VFP7的。

一. 用SQL -DMO的必要性

大部分VFPER开发的程序,都是中小规模的系统,因为这是VFP最适用的范围。而这样的系统,很多情况下是,客户端没有专业IT人士维护,更不要说专门的DBA了。对于使用SQL SERVER的系统,就带来了一些问题。 SQL SERVER是一套比较大的数据库专业软件, 是经常需要维护和清理的,而我们这些系统开发者, 总不能老跑去用户那里做维护工作吧,尤其对商业软件来说,这是很大的成本了。如果可以把对SQL SERVER的维护工作放到自己的程序里,甚至把SQL SERVER的安装无缝并入到自己的程序的安装包里,相信大家都会很乐意的。 DMO的功能就能满足我们的这些需要。通过它,可以从程序里用命令方式来操作SQL SERVER:停止/启动服务,建立数据库和表,添加用户和权限,备份/恢复数据库,数据导入/导出/发布...  DMO的作用就是把我们能在Enterprise Manager里完成的功能,完全用代码来做.

二. 微软的桌面数据引擎 (Desktop Database Engine)

我们都知道SQL SERVER 2000有四个版本: 个人版,开发者版,标准班和企业版. 其实,还有一个版本,就是桌面数据引擎(DDE)。 DDE几乎具有
SQL SERVER标准版和企业版的所有功能,不能支持的只是少数几个不常用的功能。而它和其它版本的区别是, DDE没有任何图形管理界面,没有ENTERPRISE MANAGER,没有查询分析器等等工具。 对它的管理,主要是通过DMO或者专门的API来进行,它的另一个优点是, 提供了安装程序,可以直接加到第3方软件里进行安装。每个版本的SQL SERVER CD里都带有DDE, 在MSDE目录下,运行SETUP程序就可以安装。至于怎么把它加到自己的程序里安装,大家查一下SQL SERVER的帮助文件就可以找到。
DDE的限制是: 只适宜中小型系统(比如没有5个以上的用户同时连接和运行大型SQL命令), 如果同时访问的用户很多, DDE就会比正常的SQL SERVER慢了。

这样, DDE+DMO就可以实现我们上面所要求的功能了。这种做法甚至可以不让用户知道你是在使用SQL SERVER做为数据库。当然, DMO不是只能操作DDE,它可以操作所有版本的SQL SERVER。

三. DMO的安装

其实DMO主要就是一个DLL文件而已: SQLDMO.DLL。具体位置在C:/Program Files/Microsoft SQL Server/80/Tools/Binn目录里, 在同一目录里还有个帮助文件Sqldmo80.hlp. 如果你在程序里不能使用DMO, 找到这个DLL文件,注册一下,就可以了。另外在C:/Program Files/Microsoft SQL Server/80/Tools/ Devtools/Samples/Sqldmo 目录下,有SQLDMO的例子,但都是VB和VC++的。VB的例子和VFP很接近的.


四. 初步接触DMO

在这里写几个简单的句子,来看看DMO的强大. 这些命令可以直接在命令窗口里一行一行测试, 只是用它们来显示数据库的信息。至于添加数据库,数据表,备份和恢复等比较复杂的功能,得在实例里做。

oServer=CreateObject("SQLDMO.SQLServer") &&建立SERVER对象
oServer.Connect("Snoopy","sa","778899") &&连接到你的服务器
? oServer.Databases.Count  &&显示服务器上的数据库总数
? oServer.Databases.Item(1).Name  &&显示第一个数据库的名字

oDB=oServer.Databases("PUBS") &&建立数据库对象
? oDB.Tables.Count  &&显示库里表的数目
oTable=oDB.Tables("Titles")    &&建立表对象
? oTable.Rows  &&显示表里的记录数
? oTable.Columns.Count &&显示表的列数

**显示列的属性
? oTable.Columns(1).Name
? oTable.Columns(1).type
? oTable.Columns(1).Datatype
? oTable.Columns(1).Identity
? oTable.Columns(1).InPrimaryKey


例子:


Backup和Restore数据库


oServer=CreateObject("SQLDMO.SQLServer") &&建立SERVER对象
oServer.Connect("Snoopy","sa","778899") &&连接到你的服务器

**备份
oBackup=CreateObject("SQLDMO.Backup") &&建立备份对象
oBackup.Database="PUBS" &&指定备份数据库
oBackup.Password="8899" &&给备份文件加密码
oBackup.Files="D:/Temp/PUBBack.Dat" &&指定目标文件
oBackup.SQLBackup(oServer) &&运行备份命令,速度很快的

**备份恢复
oRestore=CreateObject("SQLDMO.Restore")
oRestore.Database="PUBS"
oRestore.Files="D:/Temp/PUBBack.Dat"
oRestore.SQLRestore
oRestore.SQLRestore(oServer) &&先试不加密码,备份失败
oRestore.Password="8899"
oRestore.SQLRestore(oServer)

SQL SERVER提供几种数据库备份方式,
一种是完整备份 (Full Backup), 第二种是差异备份(Differential Backup), 第三种是日志备份, 第四种是文件备份

完整备份是把整个数据库做个备份,差异备份只是备份进行了完整备份后数据库里的新变化。当数据库很大时, 完整备份很费空间和时间,可以根据情况定期做,比如每周或者每月做一次完整备份。 其它时间可以进行差异备份,比如每天一次,或者半天一次, 也可以结合进行日志备份。文件备份是直接备份数据库的数据和日志文件。和在操作系统里做备份一样.

在恢复的时候,只要先恢复完整备份,然后恢复最后一个差异备份就可以。如果有日志备份,还需要恢复差异备份后所做的日志备份。

备份种类通过 备份对象的Action属性来决定.
oBackup.Action=0 && 参数: 0 - 完整备份,1- 差异备份,  2- 文件备份, 3 -日志备份

 


Server对象的一些属性和方法

属性
AutoReConnect: 当连接断开,后是否自动重连
ConnectionID: 本连接的ID
HostName: 本地机器的名字
Isdbcreator, Isdiskadmin, Isprocessadmin, Issecurityadmin, Isserveradmin, Issetupadmin, Issysadmin: 返回当前连接用户是否属于某类SERVER ROLE,比如是不是SA

LoginTimeout: 决定连接超时时间,默认为60秒
SaLogin: 当前连接是不是SA
Status:服务器当前状态
 VersionMajor,VersionMinor: SQL SERVER的版本号

方法:

AttachDB, DetachDB: 添加或者剥离数据库
Connect, Disconnect, Close: 连接, 断开,或者关闭当前服务器对象(oServer)
VerifyConnection: 测试当前连接是否断开
Reconnect: 重新连接
Start, Stop, Shutdown: 用来启动,停止或者关闭服务器
BeginTransaction, RollbackTransaction, CommitTransaction: 操作事务
EnumServerAttributes: 返回服务器的大部分设置参数
EnumLocks: 返回服务器上所有的加锁进程
KillProcess: 强行中断一个进程

 

在VFP里来操作和管理SQL SERVER (2) (介绍SQL-DMO)
用DMO来建立任务,并让它定时运行. 执行环境必须是NT或者WINDOWS 2000, 因为需要运行SQL AGENT

***建立任务(JOB)
oJob=CreateObject("SQLDMO.Job") &&创建任务对象
ojob.Name="Pubs_Daily_Backup" &&任务名称
oServer.JobServer.Jobs.Add(oJob) &&加到SQL SERVER的任务里
oJob.BeginAlter &&开始定义任务
oJobStep=CreateObject("SQLDMO.JobStep") &&创建任务步骤对象
oJobStep.Name = "Step_1" &&步骤名称

oJobStep.StepID = 1 &&步骤号码
oJobStep.DatabaseName="Pubs" &&数据库名称
oJobStep.SubSystem= "TSQL" &&任务类型,可以是TSQL或者操作系统命令(CmdExec), 或者ActiveScripting

cFName="PubBack"+Dtoc(Date(),1)+".dat" &&备份目标文件名
oJobStep.Command ="Backup database Pubs to Disk='D:/Temp/"+cFname+"' With Password='7788'" &&执行备份的TSQL命令
oJobStep.OnFailAction = 2  && 如果任务失败退出。也可以设成发送EMAIL或者用NT里的NETSEND发信息
oJobStep.OnSuccessAction= 1  && 如果任务成功,退出。
oJob.JobSteps.Add(oJobStep) &&添加任务步骤
oJob.StartStepID = 1 &&从第一步开始执行,对多步骤的任务起作用
oJob.DoAlter &&保存修改

***把任务加到SCHEDULER里

oJobSchedule =CreateObject("SQLDMO.JobSchedule") &&创建Schedule对象
oJob = oServer.JobServer.Jobs("Pubs_Daily_Backup")&&创建任务对象
oJobSchedule.Name = "Daily_Execution" &&名称
oJobSchedule.Schedule.FrequencyType= 4  && 运行频率, 4是每日运行
oJobSchedule.Schedule.FrequencyInterval = 1 &&运行间隔, 1是每天
oJobSchedule.Schedule.ActiveStartDate =Dtoc(Date(),1) &&开始日期(今天), 必须是yyyymmdd格式
oJobSchedule.Schedule.ActiveStartTimeOfDay = "233000" &&开始时间(晚上11点30), 必须是 hhmmss格式
**下面2句设置是使任务永不过期
oJobSchedule.Schedule.ActiveEndDate=99991231  &&no end date
oJobSchedule.Schedule.ActiveEndTimeOfDay =235959 &&No end time

添加任务到SCHEDULE里
oJob.BeginAlter
oJob.JobSchedules.Add(oJobSchedule)
oJob.DoAlter


上述命令我在VFP7里都测试成功,在SQL SERVER里也看到了新添加的命令和运行设置,但因为我是用的WINDOWS ME,没法测试任务是否真的运行了。哪位有环境,可以帮我试试


下面这个帖子中的存储过程比较麻烦,不过调用起来比较简单。

------------------------------------------------

SQL SERVER2000数据库备份和恢复存储过程

 

我自己写的2个过程和一个函数,用于SQL SERVER2000数据库备份和恢复
拿出来和大家交流一下,过程和函数的详细说明在代码中
谢谢

 


/*备份数据库的过程*/
if exists(
select * from sysobjects
  where name='pr_backup_db' and xtype='p'
          )
begin
drop proc pr_backup_db
end
go

 

create proc pr_backup_db
@flag varchar(20) out,
@backup_db_name varchar(128),
@filename varchar(1000)  --路径+文件名字
as
declare @sql nvarchar(4000),@par nvarchar(1000)
if not exists(
select * from master..sysdatabases
  where name=@backup_db_name
  )
begin
select @flag='db not exist'  /*数据库不存在*/
return
end
else
begin
if right(@filename,1)<>'/' and charindex('/',@filename)<>0
begin
  select @par='@filename varchar(1000)'
  select @sql='BACKUP DATABASE '+@backup_db_name+' to disk=@filename with init'
  execute sp_executesql @sql,@par,@filename
  select @flag='ok'
  return
end
else
begin
  select @flag='file type error'  /*参数@filename输入格式错误*/
  return
end
end

 

GO

 

说明:pr_backup_db过程是备份你的数据库

 

 

/*创建函数,得到文件得路径*/
if exists(
select * from sysobjects
  where name='fn_GetFilePath' and xtype='fn'
        )
begin
drop function fn_GetFilePath
end
go

 

create function fn_GetFilePath(@filename nvarchar(260))
returns nvarchar(260)  
as
begin
declare @file_path nvarchar(260)
declare @filename_reverse nvarchar(260)
select @filename_reverse=reverse(@filename)
select @file_path=substring(@filename,1,len(@filename)+1-charindex('/',@filename_reverse))
return @file_path
end

 


GO

 


/*恢复数据库的过程*/
if exists(
select * from sysobjects
  where name='pr_restore_db' and xtype='p'
          )
begin
drop proc pr_restore_db
end
go

 

CREATE  proc pr_restore_db   
@flag varchar(20) out,    /*过程运行的状态标志,是输入参数*/     
@restore_db_name nvarchar(128),  /*要恢复的数据名字*/
@filename nvarchar(260)         /*备份文件存放的路径+备份文件名字*/
as
declare @proc_result tinyint  /*返回系统存储过程xp_cmdshell运行结果*/
declare @loop_time smallint  /*循环次数*/
declare @max_ids smallint    /*@tem表的ids列最大数*/
declare @file_bak_path nvarchar(260)  /*原数据库存放路径*/
declare @flag_file bit   /*文件存放标志*/
declare @master_path nvarchar(260)  /*数据库master文件路径*/
declare @sql nvarchar(4000),@par nvarchar(1000)
declare @sql_sub nvarchar(4000)
declare @sql_cmd nvarchar(100)
declare @sql_kill nvarchar(100)
/*
判断参数@filename文件格式合法性,以防止用户输入类似d: 或者 c:/a/ 等非法文件名
参数@filename里面必须有'/'并且不以'/'结尾
*/
if right(@filename,1)<>'/' and charindex('/',@filename)<>0
begin
select @sql_cmd='dir '+@filename
EXEC @proc_result = master..xp_cmdshell @sql_cmd,no_output
IF (@proc_result<>0)  /*系统存储过程xp_cmdshell返回代码值:0(成功)或1(失败)*/
begin
  select @flag='not exist'   /*备份文件不存在*/
  return  /*退出过程*/
end
/*创建临时表,保存由备份集内包含的数据库和日志文件列表组成的结果集*/
create table #tem(
     LogicalName nvarchar(128), /*文件的逻辑名称*/
     PhysicalName nvarchar(260) , /*文件的物理名称或操作系统名称*/
     Type char(1),  /*数据文件 (D) 或日志文件 (L)*/
     FileGroupName nvarchar(128), /*包含文件的文件组名称*/
     [Size] numeric(20,0),  /*当前大小(以字节为单位)*/
     [MaxSize] numeric(20,0)  /*允许的最大大小(以字节为单位)*/
   )
/*
创建表变量,表结构与临时表基本一样
就是多了两列,
列ids(自增编号列),
列file_path,存放文件的路径
*/
declare @tem table(      
     ids smallint identity,  /*自增编号列*/
     LogicalName nvarchar(128),
     PhysicalName nvarchar(260),
     File_path nvarchar(260),
     Type char(1), 
     FileGroupName nvarchar(128)
   )
insert into #tem
  execute('restore filelistonly from disk='''+@filename+'''')
/*将临时表导入表变量中,并且计算出相应得路径*/
insert into @tem(LogicalName,PhysicalName,File_path,Type,FileGroupName) 
  select LogicalName,PhysicalName,dbo.fn_GetFilePath(PhysicalName),Type,FileGroupName
   from #tem
if @@rowcount>0
begin
  drop table #tem
end
select @loop_time=1
select @max_ids=max(ids)  /*@tem表的ids列最大数*/
  from @tem
while @loop_time<=@max_ids
begin
  select @file_bak_path=file_path
   from @tem where ids=@loop_time
  select @sql_cmd='dir '+@file_bak_path
  EXEC @proc_result = master..xp_cmdshell @sql_cmd,no_output
  /*系统存储过程xp_cmdshell返回代码值:0(成功)或1(失败)*/
  IF (@proc_result<>0)
   select @loop_time=@loop_time+1 
  else
   BREAK /*没有找到备份前数据文件原有存放路径,退出循环*/
end
select @master_path=''
if @loop_time>@max_ids
  select @flag_file=1   /*备份前数据文件原有存放路径存在*/
else
begin
  select @flag_file=0  /*备份前数据文件原有存放路径不存在*/
  select @master_path=dbo.fn_GetFilePath(filename)
   from master..sysdatabases
   where name='master'
end
select @sql_sub=''
/*type='d'是数据文件,type='l'是日志文件 */
/*@flag_file=1时新的数据库文件还是存放在原来路径,否则存放路径和master数据库路径一样*/
select @sql_sub=@sql_sub+'move '''+LogicalName+''' to '''
   +case type
         when 'd' then case @flag_file
             when 1 then  File_path
      else @master_path
          end   
         when 'l' then case  @flag_file
      when 1 then  File_path
      else @master_path
          end   
   end
   +case type
    when 'd' then @restore_db_name
           +'_DATA'
           +convert(sysname,ids)  /*给文件编号*/
           +'.'
           +right(PhysicalName,3)  /*给文件加入后缀名,mdf or ndf*/
           +''',' 
    when 'l' then @restore_db_name
           +'_LOG'
           +convert(sysname,ids)   /*给文件编号*/
           +'.'
           +right(PhysicalName,3)  /*给文件加入后缀名,mdf or ndf*/
           +''',' 
    end
   from @tem
select @sql='RESTORE DATABASE @db_name FROM DISK=@filename with '
select @sql=@sql+@sql_sub+'replace'
select @par='@db_name nvarchar(128),@filename nvarchar(260)'
/*关闭相关进程,把相应进程状况导入临时表中*/
select identity(int,1,1) ids, spid
  into #temp
  from master..sysprocesses
  where dbid=db_id(@restore_db_name)
if @@rowcount>0 --找到相应进程
begin  
  select @max_ids=max(ids)
   from #temp
  select @loop_time=1
  while @loop_time<=@max_ids
  begin
   select @sql_kill='kill '+convert(nvarchar(20),spid)
    from #temp
    where ids=@loop_time
   execute sp_executesql @sql_kill
   select @loop_time=@loop_time+1
  end
end
drop table #temp
execute sp_executesql @sql,@par,@db_name=@restore_db_name,@filename=@filename
select @flag='ok'   /*操作成功*/
end
else
begin
SELECT @flag='file type error'  /*参数@filename输入格式错误*/
end

 


GO

 

 

 

 


--run

 

--备份数据库test_database
declare @fl varchar(10)
execute pr_backup_db @fl out,'test_database','c:/test_database.bak'
select @fl

 

--恢复数据库,输入的参数错误
declare @fl varchar(20)
exec pr_restore_db @fl out,'sa','c:/'
select @fl

 


--恢复数据库,即创建数据库test_database的复本test_db
declare @fl varchar(20)
exec pr_restore_db @fl out,'test_db','c:/test_database.bak'
select @fl

 


以上过程和函数在MS SQL2000运行成功,由于MS SQL7不支持用户自定义函数和表变量,要在MS SQL7下使用可以把函数fn_GetFilePath改写成过

 

程,把过程pr_restore_db中的表变量改写为临时表即可运行,有兴趣的朋友可以试试!


1.数据备份:
Close All
Clear
mypath_old=Sys(5)+Sys(2003)
mypath_new=Alltrim(Alltrim(mypath_old)+'/MYDBCBF')
If !Directory("&MYPATH_new.")
Md &mypath_new.
Endif
Set Default To &mypath_new.
mydbf_old=Getfile('bak','','',1,'请输入或选定备份文件名')
If Len(mydbf_old)=0
=Messagebox('你刚才没有录入任何文件名,备份没有成功!!',32,'提示信息')
Set Default To &mypath_old.
Else
mydbf_path=Left(mydbf_old,At('/',mydbf_old,Occurs('/',mydbf_old))-1)
If !Directory("&MYDBF_path.")
Md &mydbf_path.
ENDIF
ERASE &MYDBF_old.
handle=SQLExec(con,"backup database mydbc to disk=?MYDBF_old")
Set Default To &mypath_old.
If handle>0
=Messagebox('(^_^)数据成功备份到【 '+mydbf_path+' 】文件夹下!  ',64,'数据库备份')
Else
=Messagebox(Message(),16,'数据库备份')
Endif
Endif
二.恢复:
Close All
Clear
mypath_old=Sys(5)+Sys(2003)
mypath_new=Alltrim(Alltrim(mypath_old)+'/MYDBCBF')
Set Default To &mypath_new.
mydbf=Getfile('bak','','',1,'请选定要恢复的文件名')
Restore From mypath_old+'/myurl/url' Additive
sql_server=Alltrim(my_server)
sql_path=Alltrim(Right(sql_server,Len(sql_server)-Atc('/',sql_server)))
If Len(sql_path)=0
sql_restore_mdf='C:/Program Files/Microsoft SQL Server/MSSQL/Data/mydbc.MDF'
sql_restore_ldf='C:/Program Files/Microsoft SQL Server/MSSQL/Data/mydbc_log.ldf'
Else
sql_restore_mdf='C:/Program Files/Microsoft SQL Server/MSSQL$'+sql_path+'/Data/mydbc.MDF'
sql_restore_ldf='C:/Program Files/Microsoft SQL Server/MSSQL$'+sql_path+'/Data/mydbc_log.ldf'
Endif
*now_timer=1
Try
=SQLDisconnect(con)
Catch
Finally
Endtry
=SQLSetprop(0,"displogin",3)  &&永不显示信任连接提示
myurl="driver=sql server;server="+Alltrim(my_server)+;
";uid=sa;pwd="+Alltrim(my_pwd)+;
";database=MASTER"
con_master=Sqlstringconnect(myurl)
If con_master<0
=Messagebox('<@_@>本机已与服务器失去连接,您将退出本系统!',16,'系统信息')
Else
handle=SQLExec(con_master,"RESTORE DATABASE mydbc FROM DISK=?MYDBF With Replace;
    ,Move 'MYDBC_DATA' To ?SQL_RESTORE_mdf';
,Move 'MYDBC_LOG' To ?SQL_RESTORE_LDF'")
If handle>0
=MESSAGEBOX('^_^数据恢复成功!',32,'数据恢复')
Try
=SQLDisconnect(con_master)
Catch
Finally
Endtry
=SQLSetprop(0,"displogin",3)  &&永不显示信任连接提示
myurl="driver=sql server;server="+Alltrim(my_server)+;
";uid=sa;pwd="+Alltrim(my_pwd)+;
";database=mydbc"
con=Sqlstringconnect(myurl)
If con<0
=Messagebox('<@_@>本机已与服务器失去连接,您将退出本系统!',16,'系统信息')
Else
now_timer=0
Endif
Else
=Messagebox(Message(),16,'数据恢复')
Endif
Endif
Set Default To &mypath_old.

数据备份不用多作解释.对于数据恢复:
1.要注意在选定恢复文件时可能会改变当前路径.要在恢复数据后还原当前路径.
2.测试与数据源的连接.因为SQL2000的数据库MASTER等是自带的,只要测试能否连接上其中一个就行.
  因为在恢复时可能找不到你要恢复的自定义数据库,所以要测试SQL2000的数据表.
3.SQL2000的安装可能有自定义实例这个也要考虑.比方说你的服务实例名是SERVER那SQL2000生成的文件夹是:MSSQL$SERVER而不是MSSQL
4.在恢复数据时要断开与当前数据库的连接(与上面所述,用SQL2000的自带数据库作为当前连接),否则会产生异常.
5.数据恢复成功后,要恢复与自定义数据库的连接.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值