年结功能实现(一) - Java备份还原MYSQL数据库

背景

项目中需要提供年度结算功能,年结操作时需要创建下一年度的数据库并将本年度部分数据表的数据保存到下一年度的数据库

思路

  1. 确定哪些数据表需要备份结构和数据,哪些表需要仅需要备份结构
  2. 确定备份文件存储路径(仅结构备份文件、数据&结构备份文件)
  3. 调用命令行执行数据库备份命令
  4. 合并两个备份文件
  5. 调用命令行执行数据库创建命令
  6. 调用命令行执行数据库还原命令

说明

项目中使用到了HuTools部分工具类

mysql相关命令

1. 表结构、存储过程、函数备份:
mysqldump -u[用户名] -d -R [数据库名] [需要备份的表名称,空格隔开] > [备份文件路径]

* 示例:    mysqldump -uroot -p123 -R test t1 t2 > ~/structure.sql
* 参数:   -d 仅备份结构  -R 备份存储过程及函数
* 解释:   备份test库t1、t2表结构、存储过程、函数到当前用户目录下的structure.sql文件

2. 表结构、表数据备份:
mysqldump -u[用户名] -p[密码] [数据库名] [需要备份的表名称,空格隔开] > [备份文件路径]

* 示例:    mysqldump -uroot -p123 test t3 t4 > ~/data.sql
* 解释:   备份test库t3、t4表的结构和数据到当前用户目录下的data.sql文件

3. 创建数据库:
mysqladmin -u[用户名] -p[密码] create [数据库名]

* 示例:   mysqladmin -uroot -p123 create test1
* 解释:   创建test1数据库

4. 数据库还原:
mysql -u[用户名] -p[密码] [数据库名] < [备份文件路径]

* 示例:   mysql -uroot -p123 test1 < ~/script.sql
* 解释:   将当前用户目录下的script.sql文件的内容导入到test1库

代码实现

  • 命令行执行命令工具类
import cn.apcinfo.base.exception.ApcServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BinBashUtil {

    private static final Logger log = LoggerFactory.getLogger(BinBashUtil.class);
    private static final String SYSTEM_TYPE = System.getProperty("os.name");

    /**
     * 执行指定命令
     */
    public static int execute(String cmd){
        String[] command;

        if("linux".equalsIgnoreCase(SYSTEM_TYPE)){
            command = new String[]{"/bin/sh","-c",cmd};
        } else if("windows".equalsIgnoreCase(SYSTEM_TYPE)){
            command = new String[]{"cmd","/c",cmd};
        } else {
            throw new ApcServiceException("操作系统类型不在受支持的范围内!");
        }

        // 执行命令
        try {
            Process process = Runtime.getRuntime().exec(command);
            return process.waitFor();
        } catch (Exception e) {
            log.error("执行操作系统命令失败!",e);
            throw new ApcServiceException("执行操作系统命令失败!");
        }
    }

}
  • 文件合并方法
private void mergeSQLFile(String currentFilePath,BufferedWriter targetWriter) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(currentFilePath));

   String line = null;
   while((line = br.readLine()) != null){
       // 跳过空行、注释行
       if("".equals(line.trim()) || line.startsWith("/*") || line.startsWith("--")){
           continue;
       }
       targetWriter.write(line);
       targetWriter.write(System.lineSeparator());
   }
   br.close();
}
  • 数据库备份&还原
// 准备基础参数,此处只考虑本机,如果需要操作外部服务器请提供 -h参数,并准备外部服务器host
String password = properties.getPassword();
String username = properties.getUsername();

String folderName = UUID.randomUUID().toString().replaceAll("-","");
String folderPath = StrUtil.format("{}{}{}{}",rootPath,backUpPath,folderName,File.separator);
File folder = new File(folderPath);
if(!folder.exists()){
    folder.mkdirs();
}

String onlyStructureBackUpTableStr = CollUtil.join(onlyStructureTableList," ");
String dataAndStructureBackUpTableStr = CollUtil.join(dataAndStructureTableList," ");

// 准备文件存储路径
String onlyStructureBackUpScriptFilePath = StrUtil.format("{}{}.sql",folderPath,UUID.randomUUID().toString().replaceAll("-",""));
String dataAndStructureBackUpScriptFilePath = StrUtil.format("{}{}.sql",folderPath,UUID.randomUUID().toString().replaceAll("-",""));
String completeBackUpScriptFilePath = StrUtil.format("{}{}.sql",folderPath,UUID.randomUUID().toString().replaceAll("-",""));

// 准备binbash命令
String onlyStructureBackUpCommand = StrUtil.format("mysqldump -u{} -d -R {} {} > {}",username,currentDbName,onlyStructureBackUpTableStr,onlyStructureBackUpScriptFilePath);
String dataAndStructureBackupCommand = StrUtil.format("mysqldump -u{} -p{} {} {} > {}",username,password,currentDbName,dataAndStructureBackUpTableStr,dataAndStructureBackUpScriptFilePath);
String createNextDbCommand = StrUtil.format("mysqladmin -u{} -p{} create {}",username,password,nextDbName);
String reduceCommand = StrUtil.format("mysql -u{} -p{} {} < {}",username,password,nextDbName,completeBackUpScriptFilePath);

int result = -1;
// 执行binbash命令备份数据库
try{
    result = BinBashUtil.execute(onlyStructureBackUpCommand);

    if(result != 0){
        throw new ApcServiceException("备份当前数据库失败,请稍候重试!");
    }
    result = BinBashUtil.execute(dataAndStructureBackupCommand);
    if(result != 0){
        throw new ApcServiceException("备份当前数据库失败,请稍候重试!");
    }
} catch (ApcServiceException ex){
    throw new ApcServiceException("备份当前数据库失败,请稍候重试!");
}

// 合并备份文件
try {
    BufferedWriter bw = new BufferedWriter(new FileWriter(completeBackUpScriptFilePath));
    mergeSQLFile(onlyStructureBackUpScriptFilePath,bw);
    mergeSQLFile(dataAndStructureBackUpScriptFilePath,bw);
    bw.close();

    // 清理原文件
    FileUtil.del(onlyStructureBackUpScriptFilePath);
    FileUtil.del(dataAndStructureBackUpScriptFilePath);
} catch (IOException e) {
    log.error("合并备份文件失败!",e);
    throw new ApcServiceException("合并备份文件失败!");
}

// 执行创建数据库命令
result = BinBashUtil.execute(createNextDbCommand);
if(result != 0){
    throw new ApcServiceException("创建下年度数据库失败,请稍候重试!");
}

// 执行数据库还原命令
result = BinBashUtil.execute(reduceCommand);
if(result != 0){
    throw new ApcServiceException("重置下年度数据库数据失败,请稍候重试!");
}

至此,java备份还原mysql数据库完成

结语

感谢如下博客:
mysql备份还原命令

你可能感兴趣的:(MYSQL)