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

博客介绍了MySQL开启binlog、dump方式全量备份与恢复及binlog增量备份与恢复的知识。用Java实现dump方式全量备份,可按全备加增量备份恢复一周数据;还实现基于dump全备加binlog增量的恢复,能恢复到指定时间节点,并进行了相关测试。

知识背景

背景知识参考网站: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");
    }
}

测试

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

 

全量备份后增加一条数据

 

并删除之前的一条信息

 

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

 

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

 

<think>我们参考了多个站内引用,特别是引用[1][2][3][4],它们详细介绍了MySQL增量备份恢复实现方法。根据这些引用,增量备份主要通过MySQL的二进制日志(binarylog)实现恢复时需要先恢复全量备份,再按顺序恢复所有增量备份。以下是实现MySQL增量备份恢复的完整步骤:###一、增量备份的前提条件1.**开启二进制日志**(引用[1][3][4])修改MySQL配置文件`my.cnf`(或`my.ini`):```ini[mysqld]log-bin=/var/lib/mysql/mysql-bin#启用二进制日志server-id=1#集群环境需唯一binlog_format=ROW#推荐使用ROW格式```重启MySQL服务使配置生效。2.**创建全量备份**(引用[1])增量备份前必须存在一个全量备份(基准点):```bashmysqldump-uroot-p--all-databases--single-transaction--flush-logs--master-data=2>full_backup.sql```-`--flush-logs`:生成新的二进制日志文件-`--master-data=2`:记录二进制日志位置(关键用于恢复)###二、增量备份操作步骤1.**手动触发日志轮转**(引用[3])每天备份前刷新日志,生成新二进制文件:```bashmysqladmin-uroot-pflush-logs```此时会产生新的日志文件(如`mysql-bin.000002`)。2.**备份二进制日志**(引用[1][4])将上次全量备份后产生的所有二进制日志复制到备份目录:```bashcp/var/lib/mysql/mysql-bin.00000*/backup/binlog/```###三、增量恢复操作流程1.**恢复全量备份**(引用[1][2])```bashmysql-uroot-p<full_backup.sql```2.**恢复增量备份**-**方法1:按时间点恢复**(引用[4])```bashmysqlbinlog--start-datetime="2023-01-0100:00:00"--stop-datetime="2023-01-0200:00:00"mysql-bin.000001|mysql-uroot-p```-**方法2:按位置恢复**(引用[4])```bashmysqlbinlog--start-position=296--stop-position=824mysql-bin.000057|mysql-uroot-p```-**方法3:恢复所有增量备份**(引用[2])使用脚本按顺序恢复所有增量备份文件:```bash#!/bin/bash#恢复脚本restore_incremental.shforbinlogin$(ls/backup/binlog/mysql-bin.*|sort);domysql-uroot-p<$binlogdone```###四、自动化脚本示例####增量备份脚本```bash#!/bin/bash#刷新日志生成新binlog文件mysqladmin-uroot-pYourPasswordflush-logs#备份昨日产生的二进制日志YESTERDAY=$(date-d"1dayago"+%F)BINLOG_DIR="/var/lib/mysql"BACKUP_DIR="/backup/binlog"#复制所有非当前正在写的日志文件cp$(ls-d$BINLOG_DIR/mysql-bin.*|grep-v'index')$BACKUP_DIR#清理7天前的增量备份find$BACKUP_DIR-name"mysql-bin.*"-mtime+7-delete```####全量+增量恢复脚本```bash#!/bin/bash#恢复全量备份mysql-uroot-pYourPassword</backup/full_backup.sql#恢复增量备份(按文件名顺序)ls/backup/binlog/mysql-bin.*|sort|whilereadbinlog;domysql-uroot-pYourPassword<$binlogdone```###关键注意事项1.**二进制日志安全**:增量备份依赖二进制日志,需确保其完整性[^1]。2.**恢复顺序**:必须先恢复全量备份,再按时间顺序恢复增量备份[^2]。3.**位置点恢复**:精确恢复需记录`--master-data`输出的位置点(全量备份时)[^1]。4.**性能影响**:频繁刷新日志可能影响IO性能,建议在低峰期操作[^3]。>企业级环境中,建议使用**PerconaXtraBackup**工具实现物理级别的增量备份,效率更高(引用未提供,补充说明)。§§相关问题§§1.如何验证增量备份文件的完整性?2.二进制日志(binlog)的三种格式(ROW/STATEMENT/MIXED)对备份有何影响?3.使用PerconaXtraBackup实现增量备份的具体步骤是什么?4.如何在主从复制环境中安全地进行增量备份?5.增量备份恢复过程中遇到错误如何排查?</think>### MySQL增量备份恢复完整指南 增量备份仅记录上次备份后的数据变化,具有**备份快、体积小**的优势,但恢复需依赖全量备份。以下是基于二进制日志(binlog)的标准实现方案: --- #### 一、前提条件 1. **启用二进制日志** 修改MySQL配置文件(`my.cnf`或`my.ini`): ```ini [mysqld] log-bin = /var/lib/mysql/mysql-bin # 启用binlog server-id = 1 # 集群环境需唯一 binlog_format = ROW # 推荐使用ROW格式 ``` ```bash systemctl restart mysql # 重启生效 ``` 2. **创建初始全量备份** ```bash mysqldump -u root -p --all-databases --single-transaction --flush-logs --master-data=2 > full_backup.sql ``` - `--flush-logs`:生成新binlog文件(备份基准点)[^3] - `--master-data=2`:记录当前binlog位置(关键!) --- #### 二、增量备份操作流程 1. **每日触发增量备份** ```bash mysqladmin -u root -p flush-logs # 刷新日志生成新binlog文件[^3] ``` - 新数据将写入新文件(如`mysql-bin.000003`) 2. **备份binlog文件** ```bash cp /var/lib/mysql/mysql-bin.00000* /backup/binlog/ # 复制增量日志 ``` 3. **自动化脚本示例** ```bash #!/bin/bash # 刷新日志 mysqladmin -u root -pYourPassword flush-logs # 备份昨日产生的binlog YESTERDAY=$(date -d "1 day ago" +%F) cp $(ls -t /var/lib/mysql/mysql-bin.* | grep -v 'index' | head -n 1) /backup/binlog/binlog_$YESTERDAY.bin ``` --- #### 三、增量恢复操作流程 1. **恢复全量备份** ```bash mysql -u root -p < full_backup.sql ``` 2. **恢复增量数据** - **方法1:按顺序恢复所有增量文件** ```bash # 恢复脚本 restore_incremental.sh[^2] BINLOG_DIR="/backup/binlog" for binlog in $(ls $BINLOG_DIR/mysql-bin.* | sort); do mysqlbinlog $binlog | mysql -u root -p done ``` - **方法2:精确位置恢复** ```bash mysqlbinlog --start-position=296 --stop-position=824 mysql-bin.000057 | mysql -u root -p[^4] ``` --- #### 四、关键注意事项 1. **binlog管理** - 定期清理旧binlog:`PURGE BINARY LOGS BEFORE '2023-01-01';` - 查看当前日志:`SHOW MASTER STATUS;` 2. **恢复验证工具** ```bash mysqlbinlog --verify-binlog-checksum mysql-bin.000001 # 校验日志完整性 ``` 3. **混合备份策略建议** ```mermaid graph LR A[周一全量备份] --> B[周二增量] B --> C[周三增量] C --> D[周四全量] D --> E[周五增量] ``` > **重要原则**: > - 全量备份频率 ≥ 1次/周 > - binlog保存周期 > 全量备份间隔 > - 生产环境建议使用**Percona XtraBackup**实现物理增量备份 --- #### 五、故障处理案例 **场景**:误删表`orders`,需恢复到10分钟前状态 ```bash # 1. 找到误删操作的binlog位置 mysqlbinlog --start-datetime="2023-05-01 14:00" mysql-bin.000008 | grep -C 10 "DROP TABLE orders" # 2. 恢复全量备份 + 截止到误删前的增量 mysqlbinlog --stop-position=1793 mysql-bin.000008 | mysql -u root -p ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值