今天在做毕设的最后一个模块,数据库的备份和还原。按照拿来主义的惯例,先百度一下,找找资料,很快就搞定了数据库的备份,但还原却总是出问题,最后还是搞定,在此写下记录,希望对大家有帮助。
至于备份还原数据库,肯定少不了一些基本的配置信息,如数据库的主机地址啦(host)、端口啦(port)、还有用户名、密码,以及你要操作的那个数据库的名称、存放备份文件(*.sql文件)的路径等等。
这些信息我在Spring中配置好了,如下:
<!-- 用于读取数据库的基本信息 --> <bean id="dataInfo" class="com.shutao.hr.assist.DBInfo"> <property name="dbName" value="hr"/> <property name="username" value="root"/> <property name="password" value="shutao"/> <property name="host" value="127.0.0.1"/> <property name="port" value="3306"/> <property name="dbToolsPath" value="D:/MySQL/MySQL Server 5.1/bin/"/> <property name="tablesPath" value="F:/hr/hr_tables/"/> <property name="databasePath" value="F:/hr/hr_database/"/> </bean>
然后新建一个用来操作数据库备份还原的类:DBManager。
第一步要做的当然就是读取配置信息,如下是该类的一部分代码:
static String dbName = ""; static String username = ""; static String password = ""; static String host = ""; static String port = ""; static String dbToolsPath = ""; static String databasePath = ""; static String tablesPath = ""; static String filePath = ""; //备份文件的路径 static ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml"); static { DBInfo dbInfo = (DBInfo) context.getBean("dataInfo"); dbName = dbInfo.getDbName(); username = dbInfo.getUsername(); password = dbInfo.getPassword(); host = dbInfo.getHost(); port = dbInfo.getPort(); dbToolsPath = dbInfo.getDbToolsPath(); databasePath = dbInfo.getDatabasePath(); tablesPath = dbInfo.getTablesPath(); }
生成用于备份数据库的shell命令类:
/** * 生成用于备份数据库的shell命令 * @param * targetName 要备份的对象名:只能为表名和数据库名称 * @return 实际执行的shell命令 */ public static String getBackupShellString(String targetName) { String basepath = Thread.currentThread().getContextClassLoader().getResource("").toString(); String database_tools_path = dbToolsPath; //备份的文件 String backFilePath = ""; // 若要备份整个数据库 if (targetName.equals(dbName)) { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); // 要备份的文件 backFilePath = databasePath + targetName + "_"+ sdf.format(new Date()) + ".sql"; targetName = ""; } else { backFilePath = tablesPath + targetName + ".sql"; } // 判断要备份的文件/文件夹是否已存在 File backFileFolder_db = new File(databasePath); File backFileFolder_tab = new File(tablesPath); if (!backFileFolder_db.exists()) { backFileFolder_db.mkdirs(); } if (!backFileFolder_tab.exists()) { backFileFolder_tab.mkdirs(); } String OSType = System.getProperty("os.name"); String shellStr = ""; shellStr = database_tools_path + "mysqldump -h " + host + " -P " + port + " -u " + username + " -p" //★第二个-p后面不能有空格,否则将被认为是数据库的名称 + password + " --result-file=" + backFilePath + " --default-character-set=gbk " + dbName + " " + targetName; System.out.print("##############" + shellStr); return shellStr; }
进行备份操作的类:
/** * 备份数据库 * @param * targetName 要备份的对象名:只能为表名和数据库名称 * @return 成功:TRUE 失败:FALSE * */ public static boolean backup(String targetName) { Runtime runt = Runtime.getRuntime(); Process proc; try { proc = runt.exec(getBackupShellString(targetName)); int tag = proc.waitFor();// 等待进程终止 if (tag == 0) { return true; } else { return false; } } catch (Exception e) { e.printStackTrace(); } return true; }
///还原数据库/
public static void restoreDB(String targetName) { //要读取的备份文件的路径 String fPath=""; try { if(targetName.equals(dbName)){ //这里用于测试,先指定一个数据库文件,实际应用中应根据选择来确定文件名称 fPath = databasePath+"hr_20110415161235.sql"; }else{ fPath = tablesPath+targetName+".sql"; } System.out.println("fPath:"+fPath); Runtime rt = Runtime.getRuntime(); // 调用 mysql 的 cmd: Process child = rt.exec(dbToolsPath+"mysql -uroot -pshutao "+dbName); // int tag = child.waitFor(); OutputStream out = child.getOutputStream();//控制台的输入信息作为输出流 String inStr; StringBuffer sb = new StringBuffer(""); String outStr; //下面的InputStreamReader和OutputStreamWriter的第二个参数为数据的编码格式, // 注意要跟备份的格式一样,否则会有异常:java.io.IOException: 管道已结束。 BufferedReader br=new BufferedReader(new InputStreamReader( new FileInputStream(fPath), "gbk")); while ((inStr = br.readLine()) != null) { sb.append(inStr + "/r/n"); } outStr = sb.toString(); OutputStreamWriter writer = new OutputStreamWriter(out, "gbk"); writer.write(outStr); writer.flush(); // 别忘记关闭输入输出流 out.close(); br.close(); writer.close(); System.out.println("/* Load OK! */"); } catch (Exception e) { e.printStackTrace(); } }
上面的几个方法经过测试都可以运行。
还原的时候切记注意那个编码格式,一开始用的是utf8,一直出现那个管道已结束的异常.......
一开始用的是直接用Mysql的命令来还原,但一直不成功,命令倒是可以执行,如下:
/** * 根据路径生成恢复数据库的Shell字符串 * @param targetName 要还原的对象名:只能为表名和数据库名称 * @return 恢复数据时实际执行的shell */ public static String getRestoreShellString(String targetName) { String database_tools_path = dbToolsPath; String backFile = "";// 已备份的文件 if (targetName.indexOf(dbName) == -1) {// 还原表 backFile = tablesPath + targetName + ".sql"; } else {// 还原库 backFile = databasePath + targetName; } String shellStr = ""; shellStr = database_tools_path + "mysql -h" + host + " -P" + port + " -u" + username + " -p" + password + " --default-character-set=gbk " + dbName + " < " + backFile; return shellStr; } /** * 恢复数据库 * @param targetName 要备份的对象名:只能为表名和数据库名称 * @return 成功:TRUE 失败:FALSE */ public static boolean restore(String targetName) { try { Runtime runt = Runtime.getRuntime(); Process proc ; String cmdtext = getRestoreShellString(targetName); if (System.getProperty("os.name").indexOf("Windows") != -1) { String[] cmd = { "cmd", "/c", cmdtext }; proc = runt.exec(cmd); } else { String[] cmd = { "sh", "-c", cmdtext }; proc = runt.exec(cmd); } System.out.println("cmdtext: "+cmdtext); int tag = proc.waitFor();// 等待进程终止 System.out.println("进程返回值为tag:" + tag); if (tag == 0) { return true; } else { return false; } } catch (Exception e) { e.printStackTrace(); } return false; }
具体原因暂且不去研究了,还有其他事情要做了~~乖乖用第一中读取文件流的方法吧。