JFinal 定时备份 mysql数据库 (mysqldump实现)

1. 配置文件

# windows 和  linux 不同
# database_backup_mysqldump = mysqldump
database_backup_mysqldump = C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin\\mysqldump.exe
# 数据库配置(路径不以/结尾) 注意:该目录只存放备份SQL,否则会误删其他文件
database_backup_dir = D:/home/backup
# 清除30天前的备份文件
database_backup_clear_before_days = 30
# 数据库执行备份的定时任务
cron4j=mysqlBackup
mysqlBackup.cron=0 1 * * *
mysqlBackup.class=com.sohnny.jfinal.task.BackupMySqlTask
mysqlBackup.enable=true

2.定时备份MySQL任务类

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.cron4j.ITask;
import com.sohnny.MainConfig;
import com.sohnny.jfinal.common.kit.ClearFileKit;
public class BackupMySqlTask implements ITask {
String url = MainConfig.jdbcProp.get("jdbcUrl");
Path dir = Paths.get(MainConfig.sysProp.get("database_backup_dir"));
String mysqldump = MainConfig.sysProp.get("database_backup_mysqldump");
int beforeDays = MainConfig.sysProp.getInt("database_backup_clear_before_days");
@Override
public void run() {
//获取IP和PORT
String[] arrays = url.split("/");
String host = arrays[2];
String ip, port;
if (host.contains(":")) {
ip   = host.split(":")[0];
port = host.split(":")[1];
} else {
ip = host;
port = "3306";
}
//获取数据库名称
System.out.println(arrays[3]);
System.out.println(arrays[3].substring(0, arrays[3].indexOf("?")));
String dataBaseName = arrays[3].substring(0, arrays[3].indexOf("?"));
//创建备份目录
if (!Files.exists(dir)) {
try {
Files.createDirectories(dir);
} catch (IOException e) {
e.printStackTrace();
}
}
//生成备份文件名
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"));
Path path = Paths.get(dir.toString(), dataBaseName+"-"+date+".sql");
Process process = null;
try {
String cmd = mysqldump+" -h "+ip+" -P "+port+" -u "+MainConfig.jdbcProp.get("user")+" -p"+MainConfig.jdbcProp.get("password").trim()+" --databases "+dataBaseName+" ";
System.out.println(cmd);
process = Runtime.getRuntime().exec(cmd);
            try (
        BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            ) {
backup(stdoutReader, path);
errOut(stderrReader, path);
} catch (IOException e) {
e.printStackTrace();
}
            int exitVal = process.waitFor();
            if (exitVal == 0) {
            System.out.println("数据库备份完成");
            }
            
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
//清除过期文件
ClearFileKit.clearFileByMonth(dir, beforeDays);
// 每次调度启动时,向 task_run_log 写日志,用于检查调度的时间是否与预期的一致,避免出现 bug 却不知道
Record taskRunLog = new Record().set("taskName", "backupMySql").set("createAt", new Date());
Db.save("task_run_log", taskRunLog);
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
private void backup (BufferedReader stdReader, Path path) throws IOException {
        Path backupPath = null;
        if (Files.notExists(path)) backupPath = Files.createFile(path);
        
        String line;
        try (BufferedWriter bw = Files.newBufferedWriter(backupPath, StandardOpenOption.WRITE)) {
while ((line = stdReader.readLine()) != null) {
bw.write(line+"\n");
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void errOut (BufferedReader stdReader, Path path) throws IOException {
        String line;
        try {
while ((line = stdReader.readLine()) != null) {
System.err.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Thread(new BackupMySqlTask()).start();
}
}

3. 清除过期文件类

import static java.nio.file.FileVisitResult.CONTINUE;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class ClearFileKit {
/**
 * 清除某个目录下某几天前的文件
 * @param dir
 * @param days
 */
public static void clearFileByMonth(Path dir, int days) {
class DeleteFiles extends SimpleFileVisitor<Path> {
LocalDateTime beforeDateTime = LocalDateTime.now().minusDays(days);
boolean isDeleteDir = false;
public DeleteFiles(boolean isDeleteDir) {
this.isDeleteDir = isDeleteDir;
}
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
    
        if (attr.isSymbolicLink()) {
            System.out.format("Symbolic link: %s%n ", file);
        } else if (attr.isRegularFile()) {
            try {
            boolean isHarfYearBefore = attr.creationTime().toInstant().isBefore(beforeDateTime.atZone(ZoneId.systemDefault()).toInstant());
if (isHarfYearBefore) {
Files.delete(file);
System.out.format("Delete Regular file: %s%n ", file);
}
} catch (IOException e) {
e.printStackTrace();
}
        } else {
            System.out.format("Other: %s%n ", file);
        }
        //System.out.println("(" + attr.size() + "bytes)");
        return CONTINUE;
    }
    // Print each directory visited.
    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
    
    if (isDeleteDir) {
    
    try {
    Files.delete(dir);
    System.out.format("Delete Directory: %s%n ", dir);
    } catch (NoSuchFileException x) {
    System.err.format("%s: no such" + " directory%n", dir);
    } catch (DirectoryNotEmptyException x) {
    //System.err.format("%s not empty%n", dir);
    } catch (IOException x) {
    // File permission problems are caught here.
    System.err.println(x);
    }
    }
        return CONTINUE;
    }
    // If there is some error accessing
    // the file, let the user know.
    // If you don't override this method
    // and an error occurs, an IOException 
    // is thrown.
    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        System.err.println(exc);
        return CONTINUE;
    }
    
}
long startTime = System.currentTimeMillis();
System.out.println("开始删除过期文件...");
Path startingDir = dir;
DeleteFiles pf = new DeleteFiles(false);
try {
Files.walkFileTree(startingDir, pf);
} catch (IOException e) {
e.printStackTrace();
}
    
    long endTime = System.currentTimeMillis();
    long time = endTime-startTime;
    System.out.println("删除过期文件完成, 耗时: " +time/1000+"  秒");
}
}


评论区

dominicdd

2019-05-09 09:59

点赞、收藏、评论走一波

l745230

2019-05-09 12:40

云数据库是不是就用不了了...不知道mysqldump的位置

Sohnny

2019-05-09 12:46

@l745230 只要运行环境有就行

年轻人

2019-05-10 15:40

可以,很强

maapple

2022-06-30 21:28

windows服务器备份的数据库文件乱码是咋回事@Sohnny

Sohnny

2022-09-07 14:59

这就不清楚了, 可以收到运行备份命令调试下

热门分享

扫码入社