欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog)

程序员文章站 2022-03-29 19:42:12
...

知识背景

背景知识参考网站:https://www.cnblogs.com/luoyx/p/5896419.html(有时间的话 我会抄在下面的)

开启MySQLbinlog

巴拉巴拉

dump方式全量备份与恢复

巴拉巴拉

使用binlog进行增量备份与恢复

巴拉巴拉

 

 

JAVA实现

实现dump方式的全量备份

系统每周日进行自动备份 做到可以根据全备加增量备份 恢复一周的数据的粒度.

@Component
public class Timer {
    private final Logger log = LoggerFactory.getLogger(Timer.class);

    //系统存储文件相对路径
    @Value("${application.file.path}")
    private String filepath;

    //MySql binlog 所在路径(mysql-bin.index)
    @Value("${application.mysqlbinlog.path}")
    private String binLogPath;

    //连接数据库用户名
    @Value("${spring.datasource.username}")
    private String DBUserName;

    //连接数据库密码
    @Value("${spring.datasource.password}")
    private String DBPassWord;

    @Autowired
    private BackUpListService backUpListService;

    //每周日的凌晨一点运行
    @Scheduled(cron = "0 0 1 * * 7")
    public void TimerBackUp() {
        log.debug("It's time to run TimerBackUp" + Instant.now().toString());

        BackUpListDTO backUpListDTO = new BackUpListDTO();
        backUpListDTO.setName("系统每周日凌晨自动备份");
        String realPath = filepath;
        String fpath = "BackUp";
        Calendar calendar = Calendar.getInstance();
        String dir = calendar.get(Calendar.YEAR) + "/"
            + calendar.get(Calendar.MONTH) + "/"
            + calendar.get(Calendar.DAY_OF_MONTH);

        String fileName = System.currentTimeMillis() + ".sql";

        String fullPath = realPath + "/" + fpath + "/" + dir + "/" + fileName;
        String returnPath = "/" + fpath + "/" + dir + "/" + fileName;

        File dirFile = new File(realPath + "/" + fpath + "/" + dir);
        boolean mkdirs = dirFile.mkdirs();

        try {
            //拼接mysqldump执行语句 -F 是为了刷新并开始一个新的binlog日志文件 demo为数据库名称
            String dumpEXE = "mysqldump -F -u" + DBUserName + " -p" + DBPassWord + " demo>" + fullPath;
            log.debug("dumpEXE String : " + dumpEXE);
            Process process = Runtime.getRuntime().exec("cmd /c " + dumpEXE);
            process.waitFor();
        } catch (Exception e) {
            e.getMessage();
        }

        File file = new File(fullPath);

        File binlogIndex = new File(binLogPath + "/mysql-bin.index");

        FileReader fileReader = null;
        try {
            fileReader = new FileReader(binlogIndex);
        } catch (Exception e) {
            e.getMessage();
        }
        Scanner scanner = new Scanner(fileReader);
        String line = null;
        //读取mysql-bin.index文件最后一行(即dump后所新开始的binlog文件名称,用于后续增量恢复)
        while ((scanner.hasNextLine() && (line = scanner.nextLine()) != null)) {
            if (!scanner.hasNextLine()) {
                backUpListDTO.setBinlog(line.substring(2, line.length()));
            }
        }

        backUpListDTO.setTime(Instant.now());
        backUpListDTO.setPath(returnPath);
        backUpListDTO.setSize(file.length() / 1024 / 1024 + "");

        BackUpListDTO save = backUpListService.save(backUpListDTO);
    }
}

实现基于dump全备加binlog增量的恢复

这里数据库的恢复的粒度只到达了天 可以更细分到小时分钟秒

整体思路是 : 先恢复全量备份 在根据binlog日志文件进行增量恢复到想要的时间节点.

//简单写一个接口 传递想要恢复mysql的时间点
    @GetMapping("/binlogResume")
    public ResponseEntity binlogResume(String yyyy, String MM, String dd) {
        String date = yyyy + "-" + MM + "-" + dd;
        Date parse = null;
        try {
            parse = new SimpleDateFormat("yyyy-MM-dd").parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //拿取数据库备份记录
        List<BackUpListDTO> all = backUpListExtraService.findAll(new BackUpListDTO());
        for (int i = all.size(); i > 0; i--) {
            BackUpListDTO backUpListDTO = all.get(i - 1);
            //判断是否是距离回档日期最近的全量备份信息
            if (backUpListDTO.getTime().isBefore(parse.toInstant())) {
                String path = backUpListDTO.getPath();
                String binlog = backUpListDTO.getBinlog();
                String fullpath = filepath + path;
                String binlogfullpath = binLogPath + "/" + binlog;

                //首先执行全量恢复
                String dumpEXE = "mysql -u" + DBUserName 
                    + " -p" + DBPassWord + " demo<" + fullpath;
                log.debug("dumpEXE String : " + dumpEXE);

                try {
                    Process dumpprocess = Runtime.getRuntime()
                        .exec("cmd /c " + dumpEXE);
                    dumpprocess.waitFor();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                //然后进行增量还原(先将binlog转换成.sql文件 之后运行.sql 即可)
                String binlogEXE = "mysqlbinlog --database=\"demo\" --stop-datetime=\"" 
                    + date + " 00:00:00\"" + binlogfullpath + ">" + binLogPath + "/temp.sql";
                String sqlEXE = "mysql -u" + DBUserName 
                    + " -p" + DBPassWord + " < " + binLogPath + "/temp.sql";
                log.debug("binlogEXE String : " + binlogEXE);
                log.debug("sqlEXE String : " + sqlEXE);

                try {
                    Process binlogprocess = Runtime.getRuntime()
                        .exec("cmd /c " + binlogEXE);
                    binlogprocess.waitFor();
                    Process sqlprocess = Runtime.getRuntime()
                        .exec("cmd /c " + sqlEXE);
                    sqlprocess.waitFor();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                //
                File binlogIndex = new File(binLogPath + "/mysql-bin.index");
                FileReader fileReader = null;
                try {
                    fileReader = new FileReader(binlogIndex);
                } catch (Exception e) {
                    e.getMessage();
                }
                Scanner scanner = new Scanner(fileReader);
                String line = null;
                //读取mysql-bin.index文件(判断是否有新的binlog生成 并还原)
                while ((scanner.hasNextLine() && (line = scanner.nextLine()) != null)) {
                    line = line.substring(2, line.length());
                    if (line.equals(binlog)) {
                        while ((scanner.hasNextLine() && (line = scanner.nextLine()) != null)) {
                            line = line.substring(2, line.length());
                            log.debug("" + line);

                            String binlog2EXE = "mysqlbinlog --database=\"demo\" --stop-datetime=\"" 
                                + date + " 00:00:00\"" + binLogPath + "/" 
                                + line + ">" + binLogPath + "/temp.sql";
                            String sql2EXE = "mysql -u" + DBUserName 
                                + " -p" + DBPassWord + " < " + binLogPath + "/temp.sql";
                            log.debug("binlog2EXE String : " + binlog2EXE);
                            log.debug("sql2EXE String : " + sql2EXE);

                            try {
                                Process binlog2process = Runtime.getRuntime()
                                    .exec("cmd /c " + binlog2EXE);
                                binlog2process.waitFor();
                                Process sql2process = Runtime.getRuntime()
                                    .exec("cmd /c " + sql2EXE);
                                sql2process.waitFor();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            break;
        }
        return ResponseEntity.ok().body("success");
    }
}

测试

JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog)

首先将数据库进行全量备份

JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog) 

全量备份后增加一条数据

JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog) 

并删除之前的一条信息

JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog) 

首先恢复全备信息 获得如下结果

 JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog)

再根据binlog增量恢复 获得如下结果

 JAVA调用控制台 实现MYSQL增量备份与恢复(mysqlbinlog)