本系列文章用Java实现达梦数据库的备份还原功能,分为本地备份(本服务器),异地备份(备份到其他服务器),手动备份和定时任务备份,及数据还原功能。
1. 达梦数据库备份还原分类:
代码主要通过dexp和dimp命令实现全库和表级别的逻辑备份还原
逻辑导出和逻辑导入数据库对象分为四种级别:数据库级、用户级、模式级和表级。四种级
别独立互斥,不能同时存在。四种级别所提供的功能:
1) 数据库级(FULL):导出或导入整个数据库中的所有对象。
例:./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log FULL=Y DIRECTORY=/mnt/data/dimp
2)用户级(OWNER):导出或导入一个或多个用户所拥有的所有对象。
例:./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log OWNER=USER01 DIRECTORY=/mnt/data/dimp
3)模式级(SCHEMAS):导出或导入一个或多个模式下的所有对象。
例:./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log SCHEMAS=USER01 DIRECTORY=/mnt/data/dimp
4)表级(TABLE):导出或导入一个或多个指定的表或表分区。
例:./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log TABLES=table1,table2 DIRECTORY=/mnt/data/dimp
2. 手动备份
//yum文件 dameng: dev: ip: 39.98.218.179 userName: dmdba userPwd: 123456 /** *本地服务器的ip,username,pwd写到配置文件yum中 */ @Value("${dameng.dev.ip}") private String userIp; @Value("${dameng.dev.userName}") private String userName; @Value("${dameng.dev.userPwd}") private String userPwd; /** * 手动备份 -- 部分备份 *@tnames 要备份的表名 *@copytype 备份类型 local本地 foreignLands异地 *@ip,port,user,pwd,dir 异地备份服务器的ip,port,用户名,密码,备份文件存放目录 */ public MapdumpSQL(String tnames, String copyType, String ip, String port, String user, String pwd, String dir) { System.out.println("备份类型:" + copyType); String result = null; // 保存备份列表,备份文件名称=数据库id+T+时间,还原使用 SjglSjbflbParam param = new SjglSjbflbParam(); param.setCjlx(copyType); // 获取服务器连接 if (ip != null && port != null && user != null && pwd != null && dir != null) { param.setIp(ip); param.setPort(port); param.setUsername(user); param.setRepassword(pwd); param.setDir(dir); } StringBuffer tids = new StringBuffer(); for (String s1 : ids) { tids.append(s1).append(","); } param.setTids(tids.toString().substring(0, tids.toString().length() - 1)); param.setBflx("1"); String filename = sjglSjbflbService.add(param);//将备份记录保持到数据库,还原使用 Connection conn = DMruntimeUtil.login(userIp, userName, userPwd); // 本地备份 if (copyType.equals("local")) { String dexpStr = DMruntimeUtil.dumpByTables(hostip, dbname, username, password, tnames, filename); String cmd = "cd /opt/dameng/dmdbms/bin;" + dexpStr; result = DMruntimeUtil.execute(conn, cmd); } else if (copyType.equals("foreignLands")) { // sh dexplocal.sh test2 DEV.SYS_USER root@ip:/opt/data pwd 22 String cmd = "sh /opt/dameng/dmdbms/shelldata/dexphand.sh " + filename + " " + tnames + " " + user + "@" + ip + ":" + dir + " " + pwd + " " + port; result = DMruntimeUtil.execute(conn, cmd); } /* * HttpHeaders headers = new HttpHeaders(); * headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); * headers.setContentDispositionFormData("attachment", "eval.sql"); */ Map map = new HashMap (); if (result != null) { map.put("flag", true); } else { map.put("flag", false); map.put("msg", "备份失败!"); } return map; } /** * 手动备份 -- 全部备份 */ @RequestMapping("/dumpDB") @ResponseBody public Map dumpDataBase(String[] ids, String copyType, String ip, String port, String user, String pwd, String dir) { System.out.println("备份地点:" + copyType); String result = null; SjglSjbflbParam param = new SjglSjbflbParam(); param.setCjlx(copyType); // 获取服务器连接 if (ip != null && port != null && user != null && pwd != null && dir != null) { param.setIp(ip); param.setPort(port); param.setUsername(user); param.setRepassword(pwd); param.setDir(dir); } param.setBflx("1"); String filename = sjglSjbflbService.add(param);//保持备份记录,还原使用 Connection conn = DMruntimeUtil.login(userIp, userName, userPwd); // 本地备份 if (copyType.equals("local")) { String dexpStr = DMruntimeUtil.dumpDB(hostip, dbname, username, password, filename); String cmd = "cd /opt/dameng/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); //方式2:运行脚本 // String cmd = "sh /opt/dameng/dmdbms/shelldata/fulldexphand.sh " + filename + " " + user + "@" // + ip + ":" + dir + " " + pwd + " " + port; result = DMruntimeUtil.execute(conn, cmd); } Map map = new HashMap (); if (result != null) { map.put("flag", true); } else { map.put("flag", false); map.put("msg", "备份失败!"); } return map; } }
工具类DMruntimeUtil
import ch.ethz.ssh2.Session; import com.jcraft.jsch.*; 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; /** *工具类 */ 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) { LOGGER.info("=========登录成功=========" + conn); return conn; } } catch (IOException e) { LOGGER.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); // 如果为得到标准输出为空,说明脚本执行出错了 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 hostip 数据IP地址 * @param dbName 数据库名称 * @param username 用户名 * @param password 密码 * @param excludeTables 待去除的指定表数组 */ public static String dumpByExcludeTables(String hostip, String dbName, String username, String password, String[] excludeTables) { if (ArrayUtils.isEmpty(excludeTables)) { return null; } StringBuffer result = new StringBuffer(); StringBuffer command = new StringBuffer("dmdump "); command.append(" -u").append(username).append(" -p").append(password).append(" -h").append(hostip).append(" ") .append(dbName).append(" --ignore-table="); // 遍历表数组 for (String table : excludeTables) { command.append(dbName).append(".").append(table).append(","); } return command.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) { 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=/opt/dameng/dmdbms/dm7data/EVAL/dexp"; System.out.println("命令= " + newCommand); return newCommand; } /** * 备份数据库(包括表结构与数据) * * @param hostip 数据库IP地址 * @param dbName 数据库名称 * @param username 用户名 * @param password 密码 ** 整个数据库导出 ./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) { StringBuffer command = new StringBuffer("./dexp "); command.append("USERID=").append(username).append("/").append(password).append("@").append(hostip) .append(" FILE=").append(name).append(".dmp") .append(" DIRECTORY=/opt/dameng/dmdbms/dm7data/EVAL/dexp") .append(" LOG=").append(name).append(".log FULL=Y"); System.out.println("命令= " + command.toString()); return command.toString(); } /** * 异域全部导出 * */ public static String foreignFullDumpDB(String hostip, String username, String password, String name, String reurl, String pwd, String port) { StringBuffer command = new StringBuffer("cd /opt/dameng/dmdbms/bin;"); command.append("./dexp ").append("USERID=").append(username).append("/").append(password).append("@").append(hostip) .append(" FILE=").append(name).append(".dmp") .append(" DIRECTORY=/opt/dameng/dmdbms/dm7data/EVAL/dexp") .append(" LOG=").append(name).append(".log FULL=Y;") .append("sshpass -p ").append(pwd).append(" scp -P ").append(port) .append(" /opt/dameng/dmdbms/dm7data/EVAL/dexp/").append(name).append(".dmp ") .append(reurl).append("/").append(name).append(".dmp"); return command.toString(); } public static String dimpByTables(String hostip, String dbName, String username, String password, String name, String tnames) { // ./dimp USERID=SYSDBA/SYSDBA FILE=/mnt/data/dexp/db_str.dmp LOG=db_str.log // DIRECTORY=/mnt/data/dimp StringBuffer command = new StringBuffer("./dimp "); Date date = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String str = dateFormat.format(date); String[] names = name.split("T"); command.append("USERID=").append(username).append("/").append(password).append("@").append(hostip) .append(" FILE=/opt/dameng/dmdbms/dm7data/EVAL/dexp/").append(name).append(" LOG=").append(names[0]) .append(str).append(".log").append(" TABLES=").append(tnames).append(" DIRECTORY=") .append("/opt/dameng/dmdbms/dm7data/EVAL/dimp ignore=y TABLE_EXISTS_ACTION=TRUNCATE"); String newCommand = command.toString(); System.out.println("命令= " + newCommand); return newCommand; } }