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+" 秒"); } }