Java实现SQLserver数据的备份与还原


由于项目需求,最近用到了在系统中给用户提供数据备份与还原功能,数据库为SQLserver2005,第一次遇到这种需求,做的过程也遇到了不少问题,特此记录下来,以备不时之需,同时也供有类似需求的童鞋借鉴,或者有啥好的方案,也可以拿出来大家一起交流嘛。

代码如下:

 

1.数据库工具类用于获取数据库连接,执行sql

 1 package com.bhne.web.util;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.FileInputStream;
 5 import java.io.IOException;
 6 import java.io.InputStream;
 7 import java.sql.Connection; 
 8 import java.sql.DriverManager; 
 9 import java.sql.SQLException; 
10 import java.util.Properties;
11 
12 import javax.servlet.http.HttpServletRequest;
13 
14 import org.apache.struts2.ServletActionContext;
15 
16 import com.opensymphony.xwork2.ActionContext;
17 
18 
19 public class DataBaseUtil { 
20 /** 
21 * 获取数据库连接 
22 * @return Connection 对象 
23 */ 
24 public static Connection getConnection(HttpServletRequest request) { 
25 Properties prop = new Properties(); 
26 Connection conn = null; 
27 try{
28 InputStream in = new BufferedInputStream(new FileInputStream(request.getSession().getServletContext().getRealPath("/")+"dbConfig.properties"));
29 prop.load(in); //加载属性列表
30 in.close();
31 
32 String url = prop.getProperty("url");
33 String username = prop.getProperty("username");
34 String password = prop.getProperty("password");
35 String driver = prop.getProperty("driver");
36 
37 Class.forName(driver);
38 conn = DriverManager.getConnection(url, username, password); 
39 
40 } catch (ClassNotFoundException e) { 
41 e.printStackTrace(); 
42 } catch (SQLException e) { 
43 e.printStackTrace(); 
44 } catch (IOException e) { 
45 e.printStackTrace(); 
46 } 
47 return conn; 
48 } 
49 
50 public static void closeConn(Connection conn) { 
51 if (conn != null) { 
52 try { 
53 conn.close(); 
54 } catch (SQLException e) { 
55 e.printStackTrace(); 
56 } 
57 } 
58 } 
59 }

 

2. 资源文件(dbConfig.properties),用来配置一些路径和数据库配置

#数据库配置
#url
url=jdbc:sqlserver://GSEIVR8NBYQ0FXO:1433;DatabaseName=master

#驱动程序
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver

#用户名
username=sa

#密码
password =admin

#数据库名称
dbname=TaskAssignment

#备份还原路径(该路径在数据库服务器下)
back_path=D:/back_path/

 

3.备份

/** 
* 备份数据库 
* @return backup 
* @throws IOException 
* @throws Exception 
*/ 
@RequestMapping("/backup.call")
public void backup(HttpServletRequest request,HttpServletResponse response) throws IOException { 

Map<String,Object> map = new HashMap<String,Object>();
String message = "数据库备份失败";
map.put("success", false);
map.put("message", message);
try {

Properties prop = new Properties();
InputStream in = new BufferedInputStream(new FileInputStream(request.getSession().getServletContext().getRealPath("/")+"dbConfig.properties"));
prop.load(in);
in.close();
String back_path = prop.getProperty("back_path");
String dbname = prop.getProperty("dbname"); //数据库名 
String name =dbname+ new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); //文件名
File file = new File(back_path);
String path = file.getPath() + File.separator + name + ".bak";// name文件名 
String str = "backup database "+dbname+" to disk=? with init";

PreparedStatement ps = DataBaseUtil.getConnection(request).prepareStatement(str.toString());
ps.setString(1,path);
boolean bl = ps.execute();
if(!bl){

//将生成的备份文件信息写入配置文件中
FileOutputStream oFile = new FileOutputStream(request.getSession().getServletContext().getRealPath("/")+"dbConfig.properties");//true表示追加打开
prop.setProperty("back_file", name);

prop.store(oFile, "The New properties file");
oFile.close();
map.put("success", true);
map.put("message", "数据库备份成功");
JSONObject rt = new JSONObject(map);
response.getWriter().write(rt.toString());

}
} catch (Exception e) {
map.put("success", false);
map.put("message", "数据库备份异常");
JSONObject rt = new JSONObject(map);
response.getWriter().write(rt.toString());
e.printStackTrace(); 
}

}

 

5.还原(需要调用一个存储过程)

/** 
* 数据库还原 
* @return recovery 
* @throws IOException 
*/
@RequestMapping("/recovery.call")
public void recovery(HttpServletRequest request,HttpServletResponse response) throws IOException { 

Map<String,Object> map = new HashMap<String,Object>();
map.put("success", false);
map.put("message", "数据库还原失败");
try {

Properties prop = new Properties();
InputStream in = new BufferedInputStream(new FileInputStream(request.getSession().getServletContext().getRealPath("/")+"dbConfig.properties"));
prop.load(in);
in.close();

String dbname = prop.getProperty("dbname"); //数据库名 

//备份文件路径
String name = prop.getProperty("back_file");
String back_path = prop.getProperty("back_path");
File file= new File(back_path);
String path = file.getPath()+File.separator+name+".bak";


//恢复所有连接 sql
String recoverySql = "alter database "+dbname+" set online with rollback immediate"; 

StringBuffer restoreSql = new StringBuffer();
restoreSql.append("RESTORE DATABASE ").append(dbname);
restoreSql.append(" FROM DISK=N'").append(path).append("'");
restoreSql.append(" WITH REPLACE,FILE = 1,RECOVERY,STATS = 5");

PreparedStatement ps = DataBaseUtil.getConnection(request).prepareStatement(recoverySql);
PreparedStatement rs = DataBaseUtil.getConnection(request).prepareStatement(restoreSql.toString());
CallableStatement cs = DataBaseUtil.getConnection(request).prepareCall("{call killrestore(?,?)}");

cs.setString(1, dbname); // 数据库名 
cs.setString(2, "'"+path+"'"); // 已备份数据库所在路径 
boolean bl = cs.execute(); // 关闭数据库链接进程
boolean flg = rs.execute();

boolean recoverFlg = ps.execute(); // 恢复数据库连接

if((!bl)&&(!recoverFlg)&&(!flg)){
map.put("success", true);
map.put("message", "数据库还原成功");
} 
} catch (Exception e) { 

e.printStackTrace(); 
} 
JSONObject rt = new JSONObject(map);

response.getWriter().write(rt.toString());
}

 

 

6.存储过程(需放入mster数据库中)

CREATE proc killrestore (@dbname varchar(20),@dbpath varchar(40)) 
as 
begin 
declare @sql nvarchar(500) 
declare @spid int 
set @sql='declare getspid cursor for select spid from sys.sysprocesses where dbid=db_id('''+@dbname+''')' 
exec (@sql) 
open getspid 
fetch next from getspid into @spid 
while @@fetch_status <> -1 
begin 
exec('kill '+@spid) 
fetch next from getspid into @spid 
end 
close getspid 
deallocate getspid 
end

 

全部代码供上。

 

注意事项:

        1.执行数据库备份时,生成的数据库备份文件会保存在数据库服务器所在的机器中,而不是客户机中。

        2.还原功能,大多数项目开发都是使用框架来搞的,很多人估计很疑惑,为啥还单独写一个jdbc工具类呢,是这样的,在执行数据还原之前,首先要关闭数据链接,调用的那个存储过程就是用来杀死进程的,如果使用系统链接的那个数据库来操作的话,会出现【不能kill自己的进程】,所有通过master数据链接来进行操作就可以避免这个问题了。

        3.原作者在通过存储过程进行数据还原的,但是不知道啥原因,存储过程执行的时候老是报【系统错误2】并且路径也不正确,所有我就把还原的命令拿出来单独执行了。

      

 

 

参考链接:http://blog.csdn.net/tkd03072010/article/details/6668940

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM