項目中須要提供程序上去備份數據庫,基礎代碼來自網上,可是卻留了個坑,好不容易纔趟過去……java
直接上代碼:mysql
1、備份(2018/01/03 )sql
/** * 備份mysql數據庫 * @param root mysql登陸名 * @param rootPass 登陸密碼 * @param dbName 要備份的數據庫名稱 * @param backupsPath 備份的路徑 * @param backupsSqlFileName 備份文件的名字 * @return */ public static String dbBackUp(String root,String rootPass,String dbName,String backupsPath,String backupsSqlFileName) { //生成臨時備份文件 // SimpleDateFormat sd=new SimpleDateFordckupsSqlFileName; String pathSql = backupsPath+backupsSqlFileName; try { File fileSql = new File(pathSql); if(!fileSql.exists()){ fileSql.createNewFile(); } StringBuffer sbs = new StringBuffer(); sbs.append(CMDPrefix+"mysqldump "); sbs.append(" -h 127.0.0.1 "); sbs.append(" -u "); sbs.append(root+" "); sbs.append("-p"+rootPass+" "); sbs.append(dbName); sbs.append(" --default-character-set=utf8 "); // sbs.append(">"+pathSql); sbs.append(" --result-file="+pathSql); System.out.println("cmd命令爲:——>>>"+sbs.toString()); Runtime runtime = Runtime.getRuntime(); Process child = runtime.exec(sbs.toString()); //讀取備份數據並生成臨時文件 InputStream in = child.getInputStream(); OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(pathSql), "utf8"); BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf8")); String line=reader.readLine(); while (line != null) { writer.write(line+"\n"); line=reader.readLine(); System.out.println(line); } writer.flush(); System.out.println("數據庫已備份到——>>"+pathSql); } catch (Exception e) { } return pathSql; }
注意這裏的--default-character-set=utf8設置了編碼數據庫
2、恢復緩存
出現坑的地方--default-character-set=utf8設置了編碼,若是不加這一句,頗有可能出現通道關閉的錯誤提示,另外,流的關閉順序也要注意 app
writer.close();
br.close();
out.close(); 測試
代碼:ui
public static boolean load() {//還原 try { String fPath = "e:/emaster2000DB_20180103151600.sql"; Runtime rt = Runtime.getRuntime(); // 調用 mysql 的 cmd: Process child = rt.exec(CMDPrefix+"mysql -uroot -ptime emaster2000 --default-character-set=utf8 "); OutputStream out = child.getOutputStream();//控制檯的輸入信息做爲輸出流 String inStr; StringBuffer sb = new StringBuffer(""); String outStr; BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(fPath), "utf8")); OutputStreamWriter writer = new OutputStreamWriter(out, "utf8"); int i=0; while ((inStr = br.readLine()) != null) { sb.append(inStr+"\r\n"); System.out.println(inStr); } outStr = sb.toString(); writer.write(outStr); // 別忘記關閉輸入輸出流 writer.close(); br.close(); out.close(); System.out.println("/* Load OK! */"); } catch (Exception e) { e.printStackTrace(); } return true; }
3、補充(2018/01/08)編碼
1.補充的緣由:備份的方式沒有問題,可是恢復的方式會有必定的問題,當備份出來的SQL文件很大時,在恢復時,因爲代碼是將SQL文件所有轉成流發送給cmd命令窗口,這樣會致使內存溢出。解決方式將SQL文件一部分一部分的寫,也就是使用緩存,可是因爲SQL執行的緣由,我的很擔憂會出現SQL執行問題(本人未測試),另一種方式是使用相似咱們在cmd下執行mysql的source + SQL文件路徑 這樣的命令,此處選擇第二種方式。spa
2.備份
/** * 備份mysql數據庫 * * @param root * mysql登陸名 * @param rootPass * 登陸密碼 * @param dbName * 要備份的數據庫名稱 * @param backupsPath * 備份的路徑 * @param backupsSqlFileName * 備份文件的名字 * @return */ public static String dbBackUp(String root, String rootPass, String dbName, String host,String CMDPrefix, String backupsPath, String backupsSqlFileName) { try { Runtime rt = Runtime.getRuntime(); Process pro = rt.exec(getBackupCommand(root, rootPass, dbName, host, CMDPrefix, backupsPath, backupsSqlFileName)); BufferedReader br = new BufferedReader(new InputStreamReader(pro.getErrorStream())); String errorLine = null; while ((errorLine = br.readLine()) != null) { logger.error("####################"+errorLine+"##################"); } br.close(); int result = pro.waitFor(); if (result != 0) { logger.error("####################數據庫備份失敗##################"); } } catch (IOException e) { logger.error("####################數據庫備份失敗,"+e.getMessage()+"##################"); } catch (InterruptedException e) { logger.error("####################數據庫備份失敗,"+e.getMessage()+"##################"); } catch (Exception e) { logger.error("####################數據庫備份失敗,"+e.getMessage()+"##################"); } return backupsSqlFileName; } /** * * (Javadoc) * @Title: getBackupCommand * @Description: * @param @param root 數據庫用戶名 * @param @param rootPass 數據庫用戶密碼 * @param @param dbName 數據庫名稱 * @param @param host 主機好 * @param @param CMDPrefix 命令前綴 最後須要加上\\ * @param @param backupsPath 備份路徑 * @param @param backupsSqlFileName SQL文件名稱 * @param @return * @return String[] * @throws */ private static String[] getBackupCommand(String root, String rootPass, String dbName, String host,String CMDPrefix, String backupsPath, String backupsSqlFileName) { BackupsDB.CMDPrefix=CMDPrefix; String[] cmd = new String[3]; String os = System.getProperties().getProperty("os.name"); if (os.startsWith("Win")) { cmd[0] = "cmd.exe"; cmd[1] = "/c"; } else { cmd[0] = "/bin/sh"; cmd[1] = "-c"; } StringBuilder arg = new StringBuilder(); arg.append(BackupsDB.CMDPrefix+"mysqldump "); arg.append("-u"); arg.append(root); arg.append(" -p"); arg.append(rootPass); arg.append(" --default-character-set="); arg.append(CHARSET); // arg.append(" --skip-opt "); arg.append(" --add-drop-database "); // arg.append("--routines "); arg.append("--triggers "); //arg.append("--compress "); arg.append("-r "); arg.append(backupsPath); arg.append(backupsSqlFileName); arg.append(".sql "); arg.append("--databases "); arg.append(dbName); cmd[2] = arg.toString(); return cmd; }
3.恢復
/** * * @param root * 數據庫用戶名 * @param rootPass * 數據庫密碼 * @param backupsPath * 備份文件路徑 * @param dbName * 數據庫名 * @return true 備份成功,false 備份失敗 */ public static boolean load(String root, String rootPass, String host,String CMDPrefix,String backupsPath, String dbName) {// 還原 //BackupsDB.CMDPrefix=CMDPrefix; Runtime rt = Runtime.getRuntime(); try { Process pro = rt.exec(getLoadCommand(root, rootPass, host, CMDPrefix, backupsPath, dbName)); BufferedReader br = new BufferedReader(new InputStreamReader(pro.getErrorStream())); String errorLine = null; while ((errorLine = br.readLine()) != null) { System.out.println(errorLine); } br.close(); int result = pro.waitFor(); if (result != 0) { logger.error("####################數據庫恢復失敗##################"); return false; } return true; } catch (IOException e) { e.printStackTrace(); logger.error("####################數據庫恢復失敗,"+e.getMessage()+"##################"); } catch (InterruptedException e) { logger.error("####################數據庫恢復失敗,"+e.getMessage()+"##################"); } catch (Exception e) { logger.error("####################數據庫恢復失敗,"+e.getMessage()+"##################"); } return false; } /** * * (Javadoc) * @Title: getLoadCommand * @Description: * @param @param root 數據庫用戶名 * @param @param rootPass 數據庫密碼 * @param @param host 數據庫主機好 * @param @param CMDPrefix 命令前綴路徑 * @param @param backupsPath SQL文件路徑 * @param @param dbName 數據庫名 * @param @return * @return String[] * @throws */ private static String[] getLoadCommand(String root, String rootPass, String host,String CMDPrefix,String backupsPath, String dbName) { String[] cmd = new String[3]; String os = System.getProperties().getProperty("os.name"); if (os.startsWith("Win")) { cmd[0] = "cmd.exe"; cmd[1] = "/c"; } else { cmd[0] = "/bin/sh"; cmd[1] = "-c"; } StringBuilder arg = new StringBuilder(); arg.append(BackupsDB.CMDPrefix+"mysql "); arg.append("-u"); arg.append(root); arg.append(" -p"); arg.append(rootPass); arg.append(" --default-character-set="); arg.append(CHARSET); arg.append(" "); arg.append(dbName); arg.append(" <"); arg.append(backupsPath); cmd[2] = arg.toString(); return cmd; }
注意點:1.CMDPrefix 命令前綴路徑必定是你的mysqldump和mysql的路徑
2.此處命令執行的寫法是有緣由的(主要指咱們使用 < 這個符號,在java中沒有這個定向符,cmd中是有的,全部就算拼接好的命令使用java執行和使用cmd執行是不同的),
3.備份和恢復,都要設置相同的字符編碼