通过commons

编程入门 行业动态 更新时间:2024-10-20 09:31:41

通过<a href=https://www.elefans.com/category/jswz/34/1753390.html style=commons"/>

通过commons

1、mysqldump

MYSQL本身提供了数据库备份工具 mysqldump。

可以把数据库中的表结构和数据,以 SQL 语句的形式输出到标准输出:

mysqldump -u[用户名] -p[密码] [数据库] > [备份的SQL文件]

例如,备份 demo 库到 ~/mysql.sql,用户名和密码都是 root:

mysqldump -uroot -proot demo  > ~/mysql.sql

mysqldump的详细文档

2、创建Springboot应用实现备份

创建 Spring Boot 应用,并添加 commons-exec 依赖。

<!-- .apachemons/commons-exec -->
<dependency><groupId>org.apachemons</groupId><artifactId>commons-exec</artifactId><version>1.3</version>
</dependency>

由于备份是通过新启动一个子进程调用 mysqldump 来完成,所以建议使用 apache 的 commons-exec 库。它的使用比较简单,且设计合理,包含了子进程超时控制,异步执行等等功能。

配置:

spring:# 基本的数据源配置datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/shushan?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=trueusername: rootpassword: rootapp:# 备份配置backup:# 备份数据库db: "shushan"# 备份文件存储目录dir: "backups"# 备份文件最多保留时间。如,5分钟:5m、12小时:12h、1天:1dmax-age: 3m

如上,我们配置了基本的数据源。以及自定义的 “备份配置”,其中指定了备份文件的存储目录,要备份的数据库以及备份文件滚动存储的最大保存时间。


package com.kexuexiong.service;import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;import org.apachemons.exec.CommandLine;
import org.apachemons.exec.DefaultExecutor;
import org.apachemons.exec.ExecuteWatchdog;
import org.apachemons.exec.PumpStreamHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** *  数据库备份服务* */
@Component
public class BackupService {static final Logger log = LoggerFactory.getLogger(BackupService.class);// 用户名@Value("${spring.datasource.username}")private String username;// 密码@Value("${spring.datasource.password}")private String password; // 备份数据库@Value("${app.backup.db}")private String db;// 备份目录@Value("${app.backup.dir}")private String dir;// 最大备份文件数量@Value("${app.backup.max-age}")private Duration maxAge;// 锁,防止并发备份private Lock lock = new ReentrantLock();// 日期格式化private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmmss.SSS");/*** 备份文件* @return* @throws Exception */public Path backup() throws Exception {if (!this.lock.tryLock()) {throw new Exception("备份任务进行中!");}try {LocalDateTime now = LocalDateTime.now();Path dir = Paths.get(this.dir);// 备份的SQL文件Path sqlFile = dir.resolve(Path.of(now.format(formatter) + ".sql"));if (Files.exists(sqlFile)) {// 文件已经存在,则添加后缀for (int i = 1; i >= 1; i ++) {sqlFile = dir.resolve(Path.of(now.format(formatter) + "-" + i + ".sql"));if (!Files.exists(sqlFile)) {break;}}}// 初始化目录if (!Files.isDirectory(sqlFile.getParent())) {Files.createDirectories(sqlFile.getParent());}// 创建备份文件文件Files.createFile(sqlFile);// 标准流输出的内容就是 SQL 的备份内容try (OutputStream stdOut = new BufferedOutputStream(Files.newOutputStream(sqlFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {// 监视狗。执行超时时间,1小时ExecuteWatchdog watchdog = new ExecuteWatchdog(TimeUnit.HOURS.toMillis(1));// 子进程执行器DefaultExecutor defaultExecutor = new DefaultExecutor();// defaultExecutor.setWorkingDirectory(null); // 工作目录defaultExecutor.setWatchdog(watchdog);defaultExecutor.setStreamHandler(new PumpStreamHandler(stdOut, System.err));// 进程执行命令CommandLine commandLine = new CommandLine("mysqldump");commandLine.addArgument("-u" + this.username); 	// 用户名commandLine.addArgument("-p" + this.password); 	// 密码commandLine.addArgument(this.db); 				// 数据库log.info("备份 SQL 数据");// 同步执行,阻塞直到子进程执行完毕。int exitCode = defaultExecutor.execute(commandLine);if (defaultExecutor.isFailure(exitCode)) {throw new Exception("备份任务执行异常:exitCode=" + exitCode);}}if (this.maxAge.isPositive() && !this.maxAge.isZero()) {for (Path file : Files.list(dir).toList()) {// 获取文件的创建时间LocalDateTime createTime = LocalDateTime.ofInstant(Files.readAttributes(file, BasicFileAttributes.class).creationTime().toInstant(), ZoneId.systemDefault());if (createTime.plus(this.maxAge).isBefore(now)) {log.info("删除过期文件:{}", file.toAbsolutePath().toString());// 删除文件Files.delete(file);}}}return sqlFile;} finally {this.lock.unlock();}}
}

使用 ReentrantLock 锁来保证备份任务不会被并发执行。备份文件的名称使用 yyyy-MM-dd-HHmmss.SSS 格式,包含了年月日时分秒以及毫秒,如:2023-10-22-095300.857.sql。如果文件名称冲突,则在末尾递增编号。

使用 commons-exec 启动新进程,调用 mysqldump 执行备份,备份成功后,尝试删除备份目录下那些已经 “过期” 的备份文件,从而达到滚动存储的目的。

备份成功后,返回 SQL 备份文件的 Path 对象。

更多推荐

通过commons

本文发布于:2023-12-04 19:54:46,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1662050.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:commons

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!