数据库的定期备份

2023-10-22 16:20:21 浏览数 (1)

这两天完成了数据库的定期备份业务实现,以及一些无需提及的前端页面bug更正。

因为以后可能会有不少的定期任务,如果仍然放在service目录层级下,会显得比较乱,所以决定放在了新的包schedule中。以后所有的schedule都放在这个目录层级下,方便管理,顺便截了一张当前项目的目录结构:

接下来是看一下这节的主题给springboot设置定期计划,首先,在启动类也就是DreamcenterApplication加上注解@EnableScheduling来启动定时计划的功能。然后对于mysql的定时备份代码如下:

代码语言:javascript复制
package top.dreamcenter.dreamcenter.schedule;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import top.dreamcenter.dreamcenter.entity.ServerProperties;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;

@Component
public class MysqlSchedule {

    private ServerProperties properties;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Autowired
    public MysqlSchedule(ServerProperties properties) {
        this.properties = properties;
    }

    // save data to imgBaseLocPath / mysql_bak / ...
    @Scheduled(cron = "0 0 3 * * ?")
    public void dump() {
        System.out.println("schedule [dump] run ...");

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String time = sdf.format(Calendar.getInstance().getTime());

        String path = properties.getLocalImgPath()   "mysql_bak/";
        String fileName = time   ".sql";
        File file = new File(path);

        if (file.exists() || file.mkdirs()) {
            BufferedReader bufferedReader = null;
            FileOutputStream fos = null;
            try {
                String cmd = String.format("mysqldump -u%s -p%s dreamcenter",
                        username, password);
                Process exec = Runtime.getRuntime().exec(cmd);

                System.out.println("schedule [dump] write result ...");

                bufferedReader = new BufferedReader(
                        new InputStreamReader(exec.getInputStream()));
                String temp;
                StringBuilder sb = new StringBuilder();
                while((temp = bufferedReader.readLine())!=null){
                    sb.append(temp).append("n");
                }

                fos = new FileOutputStream(path   fileName);
                fos.write(sb.toString().getBytes());

                bufferedReader.close();
                fos.close();

                System.out.println("schedule [dump] write done!");
            } catch (IOException e) {
                System.out.println("schedule [dump] write failed!");
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException ioException) {
                        System.out.println("--schedule [dump] bufferedReader");
                    }
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
            }
        }
    }
}

使用java的exec()来执行命令mysqldump【前提是该命令已经在全局环境变量中,否则需要配置填写详细的mysqldump地址执行】,然后将结果从输入流读取并且写入本地的文件中。目前导出的文件大小约莫200k,不算很大,所以就不实现自动删除久远日志的功能了,直接我全都要!

当然光就是这些的话会有非常严重的问题,因为该保存的基准路径被设置成了静态资源路径(本地图片备份后备路径需要),所以如果不对mysql_bak/进行拦截,那么这些备份文件将会被别人轻易的拿到,虽然现在没有什么特别重要的数据在库中,但是如果还是不能留下不必要的开放接口。所以同样的,需要给一个拦截注册器添加一个拦截路由,即 register.addPathPatterns("/mysql_bak/*"); 这样来防范一些意外的产生。

目前在本地测试通过了,可以实现定期备份,服务器上是否生效需要等明天凌晨三点,一定要成功欸!

0 人点赞