達夢dm數據庫遠程備份與恢復
達夢數據庫遠程操作進行備份與恢復在網絡上的參考資料與博客比較少,這里記錄下項目中用到的方法。
1、工具類
首先是編寫工具類,用於連接遠程服務器、生成相應操作的命令、執行相關命令。
package com.fongtech.cli.common.util;
import ch.ethz.ssh2.Session;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.StreamGobbler;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*工具類
*/
@Slf4j
public class DMruntimeUtil {
private static final String DEFAULT_CHARSET = "utf-8";
private static final Logger LOGGER = LoggerFactory.getLogger(DMruntimeUtil.class);
/**
* 登錄主機
*
* @return 登錄成功返回true,否則返回false
*/
public static Connection login(String ip, String userName, String userPwd) {
boolean flg = false;
Connection conn = null;
try {
conn = new Connection(ip);
conn.connect();// 連接
flg = conn.authenticateWithPassword(userName, userPwd);// 認證
if (flg) {
log.info("=========登錄服務器成功=========" + conn);
return conn;
}
} catch (IOException e) {
log.error("=========登錄服務器失敗=========" + e.getMessage());
e.printStackTrace();
}
return conn;
}
/**
* 遠程執行shll腳本或者命令
*
* @param cmd 即將執行的命令
* @return 命令執行完后返回的結果值
*/
public static String execute(Connection conn, String cmd) {
String result = "";
try {
if (conn != null) {
Session session = conn.openSession();// 打開一個會話
session.execCommand(cmd);// 執行命令
result = processStdout(session.getStdout(), DEFAULT_CHARSET);
// System.out.println("-----------result:"+result);
// 如果為得到標准輸出為空,說明腳本執行出錯了
if (StringUtils.isBlank(result)) {
LOGGER.info("得到標准輸出為空,鏈接conn:" + conn + ",執行的命令:" + cmd);
result = processStdout(session.getStderr(), DEFAULT_CHARSET);
} else {
LOGGER.info("執行命令成功,鏈接conn:" + conn + ",執行的命令:" + cmd);
}
// System.out.println(result);
conn.close();
session.close();
}
} catch (IOException e) {
LOGGER.info("執行命令失敗,鏈接conn:" + conn + ",執行的命令:" + cmd + " " + e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* 解析腳本執行返回的結果集
*
* @param in 輸入流對象
* @param charset 編碼
* @return 以純文本的格式返回
*/
private static String processStdout(InputStream in, String charset) {
InputStream stdout = new StreamGobbler(in);
StringBuffer buffer = new StringBuffer();
;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(stdout, charset));
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line + "\n");
}
} catch (UnsupportedEncodingException e) {
LOGGER.error("解析腳本出錯:" + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
LOGGER.error("解析腳本出錯:" + e.getMessage());
e.printStackTrace();
}
return buffer.toString();
}
/**
* 同城-部分備份
* 數據庫的指定表(包括表結構與數據)
*
* @param hostip 數據庫IP地址
* @param dbName 數據庫名稱
* @param username 用戶名
* @param password 密碼
* @param tables 待備份的表數組 ./dexp USERID=SYSDBA/SYSDBA@ip:port
* FILE=db_str2.dmp LOG=db_str2.log TABLES=DEV.SYS_USER
* DIRECTORY=/opt/dameng/dmdbms/dm7data/EVAL/dexp"
*/
public static String dumpByTables(String hostip, String dbName, String username, String password, String tables,
String name,String dexpFileUrl) {
StringBuffer command = new StringBuffer("./dexp ");
command.append("USERID=").append(username).append("/").append(password).append("@").append(hostip)
.append(" FILE=").append(name).append(".dmp ").append(" LOG=").append(name).append(".log ")
.append(" TABLES=").append(tables);
// int length = command.length();
String newCommand = command.toString() + " DIRECTORY="+dexpFileUrl;
log.info("命令= " + newCommand);
return newCommand;
}
/**
* 同城-全部備份
* 數據庫(包括表結構與數據)
*
* @param hostip 數據庫IP地址
* @param dbName 數據庫名稱
* @param username 用戶名
* @param password 密碼
* <p>
* 整個數據庫導出 ./dexp USERID=SYSDBA/SYSDBA@ip:port
* FILE=db_str2.dmp
* DIRECTORY=/opt/dameng/dmdbms/dm7data/EVAL/dexp
* LOG=db_str2.log FULL=Y
*/
public static String dumpDB(String hostip, String dbName, String username, String password, String name,String dexpFileUrl) {
StringBuffer command = new StringBuffer("./dexp ");
command.append("USERID=").append(username).append("/").append(password).append("@").append(hostip)
.append(" FILE=").append(name).append(".dmp")
.append(" DIRECTORY=").append(dexpFileUrl)
.append(" SCHEMAS=\"SYSDBA\" ")
// .append(" LOG=").append(name).append(".log FULL=Y");
.append(" LOG=").append(name).append(".log ");
log.info("命令= " + command.toString());
return command.toString();
}
/**
* 同城 - 刪除備份文件和備份日志
*
* @param fileName
* @return
* 刪除命令: rm -rf 20200610182738198data.log 20200610182738198data.dmp 20200611153735300dataRecover.log
*/
public static String delFile(String fileName) {
StringBuffer command = new StringBuffer("rm -rf ");
command.append(fileName+".log ").append(fileName+".dmp ")
.append(fileName+"Recover.log ");
log.info("命令= " + command.toString());
return command.toString();
}
/**
* 本地 ---數據庫恢復
* @param hostip
* @param dbname
* @param username
* @param password
* @param dir
* @return
* 恢復命令./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log
* DIRECTORY=/mnt/data/dimp
*/
public static String dimpByTables(String hostip,String dbname, String username, String password, String dir,String fileName){
StringBuffer command = new StringBuffer("./dimp ");
command.append("USERID=").append(username).append("/").append(password).append("@").append(hostip)
// .append(" FILE=").append(dbname).append(".dmp")
.append(" FILE=").append("/home/fongtech/statistic/backup/").append(fileName).append(".dmp")
.append(" SCHEMAS=\"SYSDBA\" ")
.append(" DIRECTORY=").append(dir)
.append(" TABLE_EXISTS_ACTION=APPEND ")//恢復被刪除的數據
// .append(" LOG=").append(dbname).append(".log FULL=Y");
.append(" LOG=").append(fileName).append("Recover.log "); //去掉 FULL=y
log.info("命令= " + command.toString());
return command.toString();
}
/**
* 異域--部分備份
* @param hostip
* @param username
* @param password
* @param name
* @param reurl
* @param pwd
* @param port
* @param installPath
* @param dexpFileUrl
* @return
*/
public static String foreignDumpDB(String hostip, String username, String password,
String name, String reurl, String pwd,
String port, String installPath,String dexpFileUrl,String tables) {
StringBuffer command = new StringBuffer("cd ");
command.append(installPath).append(";")
.append("./dexp ").append("USERID=").append(username).append("/").append(password).append("@").append(hostip)
.append(" FILE=").append(name).append(".dmp")
.append(" DIRECTORY=").append(dexpFileUrl)
.append(" LOG=").append(name).append(".log ")
.append(" TABLES=").append(tables);
return command.toString();
}
/**
* 異域-全部備份
*
*/
public static String foreignFullDumpDB(String hostip, String username, String password, String name,
String reurl, String pwd, String port,
String installPath,String dexpFileUrl) {
StringBuffer command = new StringBuffer("cd ");
command.append(installPath).append(";")
.append("./dexp ").append("USERID=").append(username).append("/").append(password).append("@").append(hostip)
.append(" FILE=").append(name).append(".dmp")
.append(" DIRECTORY=").append(dexpFileUrl)
.append(" LOG=").append(name).append(".log FULL=Y;");
return command.toString();
}}
2、實現
登錄服務器和數據庫的 ip 和賬戶密碼等按照實際情況設置。
文件存儲位置和達夢數據庫 /bin 等按照實際情況設置。
//用於登錄服務器
private String userIp = "xx.xxx.xxx.xx";
private String userName = "root";
private String userPwd = "123456";
//用於登錄數據庫
private String hostip = "xx.xxx.xxx.xx";
private String dbname = "SYSDBA";
private String username = "SYSDBA";
private String password = "SYSDBA";
//存儲目錄
private String dir = "/home/fongtech/statistic/backup";
//達夢數據庫的 bin 的位置
private String installPath = "/opt/dmdbms/bin";
/**
* 異步對數據庫進行備份,並且更新對應任務與生成系統消息
* @param userIp
* @param userName
* @param userPwd
* @param hostip
* @param dbname
* @param username
* @param password
* @param filename
* @param dir
* @param copyType
* @param user
* @param ip
* @param pwd
* @param port
* @param installPath
* @return
*/
@Transactional(rollbackFor = Exception.class)
@Async
public Map<String, Object> backups(String userIp,String userName,String userPwd,String hostip,
String dbname,String username,String password,String filename,
String dir,String copyType,String user,String ip,String pwd,String port,String installPath,Integer task_id){
String result = null;
String fileSize = "";
Connection conn = DMruntimeUtil.login(userIp, userName, userPwd);
// 本地備份
if (copyType.equals("local")) {
String dexpStr = DMruntimeUtil.dumpDB(hostip, dbname, username, password, filename,dir);
String cmd = "cd /opt/dmdbms/bin;" + dexpStr;
result = DMruntimeUtil.execute(conn, cmd);
} else if (copyType.equals("foreignLands")) { //異地備份
String reurl = user + "@" + ip + ":" + dir;
//方式1:運行命令
String cmd = DMruntimeUtil.foreignFullDumpDB(hostip, username, password, filename, reurl, pwd, port,installPath,dir);
//方式2:運行腳本
// String cmd = "sh /opt/dameng/dmdbms/shelldata/fulldexphand.sh " + filename + " " + user + "@"
// + ip + ":" + dir + " " + pwd + " " + port;
result = DMruntimeUtil.execute(conn, cmd);
}
Map<String, Object> map = new HashMap<String, Object>();
if (result != null) {
map.put("flag", "success");
//獲取文件大小 todo 待測試!!!!!!!!!!!!!
conn = DMruntimeUtil.login(userIp, userName, userPwd);
String sizeCmd = "cd "+dir+";"+" du -sh "+filename+".dmp";
String resultSize = DMruntimeUtil.execute(conn, sizeCmd);
if(resultSize.contains("M")){
String[] ms = resultSize.split("M");
fileSize = ms[0]+"M";
}else if (resultSize.contains("K")){
String[] ms = resultSize.split("K");
fileSize = ms[0]+"K";
}else if (resultSize.contains("G")){
String[] ms = resultSize.split("G");
fileSize = ms[0]+"G";
}
log.info("--------獲取備份文件的大小 fileSize:"+fileSize);
// System.out.println("-------resultSize:"+resultSize);
// System.out.println("-------fileSize:"+fileSize);
} else {
map.put("flag", "failed");
map.put("msg", "備份失敗!");
}
// 如果執行成功,對任務進行更新,, 並且需要有消息提示
CommonTask one = commonTaskService.query().eq(CommonTask::getId, task_id).getOne();
// one.setTask_start(new Date());
// System.out.println(one);
if(result!=null){
one.setTask_status("task_12");
one.setTask_end(new Date());
}else {
one.setTask_status("task_15");
one.setTask_end(new Date());
}
commonTaskService.saveBackupsTask(one,filename,fileSize,dir);
return map;
}
上面的實現是備份,恢復和刪除同理。