• NBlog Java定时任务-备份MySQL数据


    NBlog部署维护流程记录(持续更新):https://blog.csdn.net/qq_43349112/article/details/136129806

    为了避免服务器被攻击,给博客添加了一个MySQL数据备份功能。

    此功能是配合博客写的,有些方法直接用的已有的,不会再详细展示代码。

    备份大致功能步骤如下:

    • 使用mysqldump备份数据(完成)
    • 对备份文件进行压缩(完成)
    • 压缩文件上传到OSS(完成)
    • 文件清理(完成)
    • 邮件通知(TODO)
    • 适应化改造(TODO)

    详细步骤见下文

    CG

    0.备份任务主逻辑

    目前暂时使用定时任务触发,以下仅为核心代码。

        /**
         * 定时任务,每周一凌晨四点,备份MySQL的数据
         * 备份逻辑:
         * 1.mysql数据备份到文件
         * 2.备份文件压缩
         * 3.压缩文件上传到OSS
         * 4.残留文件清理
         * 5.备份结果的邮件通知 //TODO
         * 6.适应化改造,改成类似NBlog中的定时任务 //TODO
         */
        @Scheduled(cron = "0 0 4 * * 1")
        public void backUpMySQLData() {
            checkDir(backupDir);
            String dateFormat = simpleDateFormat.format(new Date());
            String fileName = String.format("cblog-%s.sql", dateFormat);
            String compressedFileName = fileName + ".zip";
            String dataPath = backupDir + File.separator + fileName;
            String compressedFilePath = backupDir + File.separator + compressedFileName;
            try {
                log.debug("mysql备份开始");
                // 1.mysql数据备份
                backupData(dataPath);
                // 2.文件压缩
                FileUtils.compressFile(dataPath, compressedFilePath);
                // 3.上传到OSS
                String uploadLink = UploadUtils.upload(compressedFilePath);
                log.info("备份文件({})已上传至OSS({})", compressedFilePath, uploadLink);
                // 4.清除残留文件
                FileUtils.delFileByPath(dataPath, compressedFilePath);
            } catch (IOException e) {
                log.error("mysql数据备份失败");
                log.error(e.getMessage());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    1.mysqldump备份

    通过Runtime.getRuntime().exec(xxx)执行备份命令,保存到指定路径下。

    由于我的MySQLdocker部署,因此使用了docker exec命令。

    命令的执行结果会比较长,日志级别建议低一些,下面用的debug级别。

    需要注意exec(cmds)的参数格式,写错的话命令不会执行并且不报错,排查了半个下午。

        /**
         * MySQL数据备份
         * @param dataPath 备份文件的保存路径
         * @throws IOException
         */
        private void backupData(String dataPath) throws IOException {
            long start = System.currentTimeMillis();
            String cmd = String.format("docker exec mysql mysqldump -u%s -p%s cblog > %s", dataSourceProperties.getUsername(), dataSourceProperties.getPassword(), dataPath);
            String[] cmds = {"sh", "-c", cmd};
            log.debug("欲执行命令:{}", cmd);
            try (InputStream inputStream = Runtime.getRuntime().exec(cmds).getInputStream();
                 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
                 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
                String line = bufferedReader.readLine();
                while (line != null) {
                    log.debug(line);
                    line = bufferedReader.readLine();
                }
            }
            long end = System.currentTimeMillis();
            log.info("mysql备份命令执行成功,耗时:{}ms", end - start);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    2.备份文件压缩

    压缩成zip格式,核心代码如下:

         * 压缩文件到指定路径
         * @param oriFilePath 要压缩的原文件路径
         * @param compressedFilePath 压缩后的文件存放路径
         * @throws IOException IO异常,不在catch模块捕捉,交给调用方自行处理
         */
        public static void compressFile(String oriFilePath, String compressedFilePath) throws IOException {
            File file = new File(oriFilePath);
            File zipFile = new File(compressedFilePath);
            try (FileInputStream fileInputStream = new FileInputStream(file);
                 ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))){
                zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
                int temp = 0;
                while ((temp = fileInputStream.read()) != -1) {
                    zipOutputStream.write(temp);
                }
            }
            log.info("文件压缩完成");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    3.上传至OSS

    核心代码如下

        public String upload(String filepath) throws IOException {
            File file = new File(filepath);
            String uploadName = aliyunProperties.getBackupPath() + "/" + file.getName();
            PutObjectRequest putObjectRequest = new PutObjectRequest(aliyunProperties.getBucketName(), uploadName, file);
            return uploadByOSS(putObjectRequest, uploadName);
        }
    
        private String uploadByOSS(PutObjectRequest putObjectRequest, String uploadName) throws IOException {
            try {
                ossClient.putObject(putObjectRequest);
                return String.format("https://%s.%s/%s", aliyunProperties.getBucketName(), aliyunProperties.getEndpoint(), uploadName);
            } catch (Exception e) {
                throw new RuntimeException("阿里云OSS上传失败");
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.清除残留文件

    上传后,备份文件和压缩文件已经无用,删除掉即可:

        public static void delFileByPath(String... paths) {
            if (paths == null) {
                return;
            }
            for (String path : paths) {
                File file = new File(path);
                del(file);
            }
        }
    
        private static void del(File file) {
            String filePath = file.getAbsolutePath();
            file.delete();
            log.info("{}文件已清除", filePath);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5.邮件通知结果(TODO)

    6.适应化改造(TODO)

    NBlog定时任务可以在前端配置,自由修改触发时间,并且可以直接触发。

    目前的暂时写死了,下周改造下。

    X、测试

    确定定时任务触发后,OSS能看到文件即可

    image-20240317171232043

  • 相关阅读:
    Deno 命令行界面
    举个栗子~Minitab 技巧(3):用分组条形图快速对比数据
    map reduce案例超详细讲解
    Win7使用默认用户登录
    这不会又是一个Go的BUG吧?
    Ajax用法总结
    Python 简介
    详解和实现数据表格中的行数据合并功能
    泡咖啡问题
    java计算机毕业设计web开发数码产品推荐平台系统设计与实现源码+mysql数据库+系统+lw文档+部署
  • 原文地址:https://blog.csdn.net/qq_43349112/article/details/136785537