李林
2023-12-19 1cb9a7d2e9dfd915a0d25e3706f62e4b5b959947
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package com.yuanchu.mom.backup;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
 
@Component
@EnableScheduling
@Slf4j
public class MysqlDataBackup {
    /**
     * 数据库版本是否为 8.0 + (false=否  true=是), mysql8+ 需要参数  --column-statistics=0  , mysql8- 不需要
     */
    Boolean isDbVersion8 = false;
 
    /**
     * 备份命令
     * USERNAME   账号
     * PASSWORD   密码
     * SERVERPATH 服务器IP/域名
     * DBNAME     数据库名称
     * FILEPATH   备份文件存放地址+名称
     * 说明
     * cmdCompression : 需压缩 (本地或服务器需安装 mysqldump 命令(安装mysql自带患独立安装) +  gzip 命令(独立安装))
     * cmd :            不压缩 (本地或服务器需安装 mysqldump 命令(安装mysql自带患独立安装)
     * --column-statistics=0     mysql8 添加该参数, 非mysql8 不添加, 否则将出错
     */
    String cmdMysql8 = "mysqldump --column-statistics=0  -u{USERNAME} -p{PASSWORD} -h{SERVERPATH} -P3306 --databases {DBNAME}"; //  > {FILEPATH}.sql
    String cmd = "mysqldump -u{USERNAME} -p{PASSWORD} -h{SERVERPATH} -P3306 --databases {DBNAME}";      //  > {FILEPATH}.sql
 
    /**
     * 备份 sql 存放目录(相对路径, 注意可能需要在 MvcConfig 配置访问权限)
     */
    @Value("${backup.path}")
    private String filePath;
 
    @Value("${spring.datasource.url}")
    private String dbUrl;
 
    @Value("${spring.datasource.username}")
    private String dbUserName;
 
    @Value("${spring.datasource.password}")
    private String dbPassWord;
 
    @Value("${backup.destiny}")
    private Integer destiny;
 
    @Value("${backup.mysqldump}")
    private String mysqldump;
 
    /**
     * 每天晚上23点05秒执行 【  0 0 4 1/1 * ? 】
     * 测试 20 秒一次【  0/20 * * * * ? 】@Scheduled(cron = "5 * 23 * * ?")
     */
    @Scheduled(cron = "5 0 23 * * ?")
    private void configureTasks() {
        log.info("【备份数据库】--START");
        String dbUrl2 = dbUrl.replace("jdbc:mysql://", "");
 
        // 获取数据库名称
        String dbName = dbUrl2.substring(dbUrl2.lastIndexOf("/") + 1, dbUrl2.indexOf("?"));
        // 获取数据库地址
        String serverPath = dbUrl2.substring(0, dbUrl2.lastIndexOf(":"));
        // 数据库账号
        String username = dbUserName;
        // 数据库密码
        String password = dbPassWord;
 
        // 备份文件目录+名称  备份文件存放目录+名称(名称 = 数据库名+时间字符串.sql)
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String format = simpleDateFormat.format(new Date());
        String timeStr = format
                .replaceAll("-", "_")
                .replaceAll(" ", "_")
                .replaceAll(":", "");
        timeStr = timeStr.substring(0, 15);
        String pathFileName = filePath + "/" + dbName + "_" + timeStr + ".sql";
        String newCmd = "";
        if (isDbVersion8) {
            newCmd = cmdMysql8;
        } else {
            newCmd = cmd;
        }
        // 执行命令
        newCmd = newCmd.replace("{USERNAME}", username)
                .replace("{PASSWORD}", password)
                .replace("{SERVERPATH}", serverPath)
                .replace("{DBNAME}", dbName)
                .replace("{FILEPATH}", pathFileName);
        PrintWriter printWriter = null;
        BufferedReader bufferedReader = null;
        try {
            // 创建存放sql的文件
            existsFile(new File(pathFileName));
            printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(pathFileName), "utf8"));
            Process process = null;
            String property = System.getProperty("os.name");
            System.out.println(property);
            if (property.indexOf("Linux") != -1) {
                // linux
                process = Runtime.getRuntime().exec(new String[]{"bash", "-c", newCmd});
            } else {
                // 本地win
                String mysqldumpPath = "cmd /c " + mysqldump + "/" + newCmd;
                System.out.println(mysqldumpPath);
                process = Runtime.getRuntime().exec(mysqldumpPath);
            }
            InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), "utf8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                printWriter.println(line);
            }
            // 此次会执行过长时间,直到备份完成
            printWriter.flush();
            printWriter.close();
            //0 表示线程正常终止。
            if (process.waitFor() == 0) {
                // 线程正常执行
                log.info("【备份数据库】SUCCESS,SQL文件:{}", pathFileName);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("【备份数据库】FAILURE");
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (printWriter != null) {
                    printWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        log.info("【备份数据库】--END");
    }
 
 
    /**
     * 每天晚上23点0分10秒执行 【  0 0 4 1/1 * ? 】
     * 测试 20 秒一次【  0/20 * * * * ? 】
     */
    @Scheduled(cron = "6 0 23 * * ?")
    private void TimerDeleteFile(){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("d");
        Integer currentDay = Integer.valueOf(sdf.format(date));
        File file = new File(filePath);
        File[] files = file.listFiles();
        if (files != null) {
            for(File f : files){
                if(f.isFile()){//若是文件,直接打印
                    String[] splitFile = f.getName().split("_");
                    Integer fileDay = Integer.valueOf(splitFile[splitFile.length - 2]);
                    Integer i = currentDay - fileDay;
                    if (i.equals(destiny)){
                        f.delete();
                        log.info("备份sql文件过多进行删除!");
                    }
                }
            }
        }
    }
 
    /**
     * 判断文件是否存在,不存在创建
     */
    private static void existsFile(File file) {
        // 判断文件路径是否存在,不存在新建
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}