最近写了一个 MySQL 数据库自动、手动备份管理系统开源项目,想跟大家分享一下,项目地址:

https://gitee.com/asurplus/db-backup

1、界面献上

登录界面


首页


实例管理


执行备份


任务管理


备份记录

2、引入依赖

<!--用于动态创建数据库连接-->
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>4.0.3</version>
</dependency>
<!-- mysql连接驱动 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 定时任务 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- Sa-Token-Quick-Login 插件 -->
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-quick-login</artifactId><version>1.30.0</version>
</dependency>

3、Sa-Token-Quick-Login 快速登录插件

如果你开发了一个小系统,并不需要多用户登录,但是必须得有登录,你又不想写登录,那么用 Sa-Token-Quick-Login 快速登录插件 是你的不二选择,具体用法参考:【SpringBoot】59、SpringBoot使用Sa-Token-Quick-Login插件快速登录认证

https://lizhou.blog.csdn.net/article/details/123571910

4、动态创建数据库连接

  • 1、拼接连接地址
/*** 拼接url** @param host* @param port* @return*/
public static String getUrl(String host, String port, String database) {if (StringUtils.isBlank(database)) {database = "mysql";}return "jdbc:mysql://" + host + ":" + port + "/" + database + "?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=true&characterEncoding=UTF-8";
}

我们通过 ip,端口就能动态创建数据库连接,因为每个数据库实例中都有 “mysql” 数据库,我们默认使用 “mysql” 数据库来创建连接

  • 2、获取数据库连接配置
/*** 数据库连接配置** @param properties 数据库连接信息* @return*/
public static HikariConfig getHikariConfig(DbProperties properties) {HikariConfig hikariConfig = new HikariConfig();hikariConfig.setDriverClassName(properties.getClassName());hikariConfig.setJdbcUrl(getUrl(properties.getHost(), properties.getPort(), properties.getDatabase()));hikariConfig.setUsername(properties.getUsername());hikariConfig.setPassword(properties.getPassword());hikariConfig.setMaximumPoolSize(2);hikariConfig.setMinimumIdle(1);hikariConfig.setAutoCommit(true);hikariConfig.setConnectionTestQuery("SELECT 1 FROM DUAL");hikariConfig.addDataSourceProperty("cachePrepStmts", "true");hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250");hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");return hikariConfig;
}
  • 3、创建数据源
/*** 创建数据源** @param hikariConfig* @return*/
public static HikariDataSource createDataSource(HikariConfig hikariConfig) {if (null == hikariConfig) {return null;}return new HikariDataSource(hikariConfig);
}

这样我们就能得到 HikariDataSource 数据源了,可以用来执行 SQL 语句,例如:查询实例中的数据库,查询数据库中的数据表,对数据表中的数据实现 “增删改查” 操作

  • 4、获取实例中的所有数据库
/*** 获取数据库信息*/
public static List<String> listDataBases(DataSource dataSource) {try {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);List<String> databases = jdbcTemplate.query("SHOW DATABASES", new RowMapper<String>() {public String mapRow(ResultSet rs, int rowNum) throws SQLException {return rs.getString(1);}}, null);return DbUtil.filterDatabase(databases);} catch (Exception e) {log.error("获取数据库信息失败:{}", e.getMessage());}return null;
}

使用 “show databases” SQL 语句,查询实例中的所有数据库信息,因为实例中包含 MySQL 的默认数据库,我们需要将其过滤掉,如下:

private static final List<String> FILTER_DATABASE = Arrays.asList("information_schema", "mysql", "performance_schema", "sys");public static List<String> filterDatabase(List<String> list) {if (CollectionUtil.isEmpty(list)) {return null;}List<String> resList = new ArrayList<>();for (String item : list) {if (!FILTER_DATABASE.contains(item)) {resList.add(item);}}return resList;
}
  • 5、获取数据库中的所有数据表
/*** 获取数据表信息*/
public static List<String> listTables(DataSource dataSource) {try {JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);List<String> databases = jdbcTemplate.query("SHOW TABLES;", new RowMapper<String>() {public String mapRow(ResultSet rs, int rowNum) throws SQLException {return rs.getString(1);}}, null);return databases;} catch (Exception e) {log.error("获取数据表信息失败:{}", e.getMessage());}return null;
}

使用 “show tables” SQL 语句,查询数据库中的所有数据表信息

5、数据库备份

  • 1、公共参数
/*** 项目路径*/
public static final String PROJECT_PATH = System.getProperty("user.dir");/*** 当前系统类型*/
public static final String OS_NAME = System.getProperty("os.name");
  • 2、拼接备份数据库命令
/*** 拼接备份sql命令** @param host     主机地址* @param port     端口* @param dbName   数据库名称* @param tables   表格名称* @param dataType 备份参数【0-表结构1-表数据 else 表结构+表数据】* @param username 用户名* @param password 密码* @param path     备份文件目录* @param fileName 备份文件名* @return*/
public static String[] createBackupCommand(String host, String port, String dbName, String[] tables, Integer dataType, String username, String password, String path, String fileName) {String[] commands = new String[3];if (OS_NAME.startsWith("Win")) {commands[0] = "cmd.exe";commands[1] = "/c";} else {commands[0] = "/bin/sh";commands[1] = "-c";}// 拼接命令StringBuilder mysqldump = new StringBuilder();mysqldump.append("mysqldump");mysqldump.append(" --opt");// 用户,密码mysqldump.append(" --user=").append(username);mysqldump.append(" --password=").append(password);// ip,端口mysqldump.append(" --host=").append(host);mysqldump.append(" --port=").append(port);// 使用的连接协议,包括:tcp, socket, pipe, memorymysqldump.append(" --protocol=tcp");// 设置默认字符集,默认值为utf8mysqldump.append(" --default-character-set=utf8");// 在导出数据之前提交一个BEGIN SQL语句,BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态mysqldump.append(" --single-transaction=TRUE");// 导出存储过程以及自定义函数mysqldump.append(" --routines");// 导出事件mysqldump.append(" --events");// 只备份表结构if (null != dataType) {if (0 == dataType) {mysqldump.append(" --no-data");}// 只备份表数据else if (1 == dataType) {mysqldump.append(" --no-create-info");}}// 数据库名mysqldump.append(" ").append(dbName);// 数据表名if (null != tables && 0 < tables.length) {for (String item : tables) {mysqldump.append(" ").append(item);}}// 保存文件路径mysqldump.append(" > ").append(path).append(fileName);commands[2] = mysqldump.toString();return commands;
}
  • 3、执行备份数据库命令
/*** @param host     主机地址* @param port     端口* @param dbName   数据库名称* @param tables   表格名称* @param dataType 备份参数【0-表结构1-表数据 else 表结构+表数据】* @param username 用户名* @param password 密码* @return*/
public BackRespVO backup(String host, String port, String dbName, String[] tables, Integer dataType, String username, String password) {// 返回对象BackRespVO respVO = new BackRespVO();try {// 当前年月日String ymd = MysqlTool.getDate();// 文件目录String path = PROJECT_PATH + File.separator + "static" + File.separator + ymd + File.separator;// 文件名String fileName = IdUtil.fastSimpleUUID() + ".sql";// 创建文件File file = new File(path, fileName);// 路径不存在,则新建if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}// shell 命令脚本String[] commands = createBackupCommand(host, port, dbName, tables, dataType, username, password, path, fileName);Runtime runtime = Runtime.getRuntime();Process process = runtime.exec(commands);// 备份成功if (process.waitFor() == 0) {respVO.setFile(file);return respVO;}// 备份失败else {InputStream is = process.getErrorStream();if (is != null) {BufferedReader in = new BufferedReader(new InputStreamReader(is, OS_NAME.startsWith("Win") ? "GBK" : "UTF-8"));String line;StringBuilder sb = new StringBuilder();while ((line = in.readLine()) != null) {sb.append(line);}respVO.setMsg("【" + dbName + "】备份失败,原因:" + sb);respVO.setFile(file);}}} catch (Exception e) {respVO.setMsg("【" + dbName + "】备份失败,原因:" + e.getMessage());}return respVO;
}
  • 4、执行备份任务,并保存备份记录
/*** 异步执行备份任务,保存备份记录** @param dbId         实例id* @param host         主机地址* @param port         端口* @param dbName       数据库名* @param tables       数据表名* @param dataType     备份参数【0-表结构1-表数据 else 表结构+表数据】* @param username     用户名* @param password     密码* @param startTime    开始时间* @param categoryEnum 备份类型(手动备份,自动备份)*/
@Async
public void saveBackUp(Integer dbId, String host, String port, String dbName, String[] tables, Integer dataType, String username, String password, Date startTime, BackupCategoryEnum categoryEnum) {// 执行备份BackRespVO respVO = backup(host, port, dbName, tables, dataType, username, password);// 备份失败if (!respVO.isSuccess()) {if (null != respVO.getFile()) {respVO.getFile().delete();}}// 保存备份记录BackupLog backupLog = new BackupLog();backupLog.setDbId(dbId);backupLog.setCategory(categoryEnum.getMsg());backupLog.setDatabaseName(dbName);backupLog.setTablesName(StringUtils.join(tables, ","));backupLog.setDataType(dataType);backupLog.setStatus(respVO.isSuccess());backupLog.setMsg(respVO.getMsg());// 备份成功if (respVO.isSuccess()) {// 文件相对路径backupLog.setFilePath(respVO.getFile().getPath().replace(MysqlTool.PROJECT_PATH + File.separator, ""));backupLog.setFileSize(respVO.getFile().length());}// 开始时间backupLog.setStartTime(startTime);backupLog.setEndTime(new Date());backupLog.setSpendTime(backupLog.getEndTime().getTime() - backupLog.getStartTime().getTime());backupLogMapper.insert(backupLog);
}

我们采用异步执行的方式,因为备份过程可能会很漫长,执行备份了之后,得到备份的文件路径,保存在备份记录中,可以实时进行查看

6、添加自动备份定时任务

定时任务主要依赖 quartz,可以动态管理定时任务,非常方便

  • 1、定时任务管理工具类
import cn.hutool.core.collection.CollectionUtil;
import com.asurplus.entity.BackupTask;
import com.asurplus.mapper.BackupTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;/*** quartz工具类** @Author Asurplus*/
@Slf4j
@Component
public class QuartzManager {/*** 参数传递key*/public static final String PARAM_KEY = "params";/*** 执行任务类名*/public static final String CLASS_NAME = "com.asurplus.job.DbBackupJob";/*** 程序调度器*/@Autowiredprivate Scheduler scheduler;@Resourceprivate BackupTaskMapper backupTaskMapper;/*** 系统启动执行*/@PostConstructpublic void init() {List<BackupTask> list = backupTaskMapper.selectList(null);if (CollectionUtil.isNotEmpty(list)) {for (BackupTask item : list) {try {add(item.getId(), item.getCron(), item.getParam(), item.getStatus());} catch (Exception e) {log.error(e.getMessage());}}}}/*** 添加定时任务*/public void add(Integer id, String cronExpression, String param, Boolean status) {try {// 构建job信息JobDetail jobDetail = JobBuilder.newJob(getClass(CLASS_NAME).getClass()).withIdentity(getKey(id)).usingJobData(PARAM_KEY, param).build();// 表达式调度构建器(即任务执行的时间)CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);// 按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getKey(id)).withSchedule(scheduleBuilder).build();// 创建定时任务scheduler.scheduleJob(jobDetail, trigger);// 停止if (!status) {stop(id);}} catch (Exception e) {log.error("添加定时任务失败:{}", e.getMessage());}}/*** 编辑定时任务*/public void update(Integer id, String cronExpression, String param, Boolean status) {try {// 判断是否存在,存在先删除if (scheduler.checkExists(JobKey.jobKey(getKey(id)))) {scheduler.deleteJob(JobKey.jobKey(getKey(id)));}// 再创建add(id, cronExpression, param, status);} catch (Exception e) {log.error("修改定时任务失败:{}", e.getMessage());}}/*** 暂停任务*/public void stop(Integer id) {try {scheduler.pauseJob(JobKey.jobKey(getKey(id)));} catch (SchedulerException e) {// 暂停定时任务失败log.error("暂停定时任务失败:{}", e.getMessage());}}/*** 恢复任务*/public void start(Integer id) {try {scheduler.resumeJob(JobKey.jobKey(getKey(id)));} catch (SchedulerException e) {// 暂停定时任务失败log.error("启动定时任务失败:{}", e.getMessage());}}/*** 立即执行一次*/public void run(Integer id) {try {scheduler.triggerJob(JobKey.jobKey(getKey(id)));} catch (SchedulerException e) {// 暂停定时任务失败log.error("执行定时任务失败:{}", e.getMessage());}}/*** 删除定时任务*/public void delete(Integer id) {try {// 停止触发器scheduler.pauseTrigger(TriggerKey.triggerKey(getKey(id)));// 移除触发器scheduler.unscheduleJob(TriggerKey.triggerKey(getKey(id)));// 删除任务scheduler.deleteJob(JobKey.jobKey(getKey(id)));} catch (Exception e) {log.error("删除定时任务失败:{}", e.getMessage());}}/*** 根据类名获取类*/private Job getClass(String className) throws Exception {Class<?> class1 = Class.forName(className);return (Job) class1.newInstance();}/*** 拼接key** @return*/public String getKey(Integer id) {return "dbBackUp-" + id;}
}

包含对定时任务的 “增删改查” 操作,默认执行 job 为:com.asurplus.job.DbBackupJob

2、备份任务

import com.alibaba.fastjson.JSONObject;
import com.asurplus.config.quartz.QuartzManager;
import com.asurplus.enums.BackupCategoryEnum;
import com.asurplus.utils.MysqlTool;
import com.asurplus.vo.BackupJobVO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;import java.util.Date;/*** 备份定时任务*/
@Slf4j
public class DbBackupJob implements Job {@Autowiredprivate MysqlTool mysqlTool;@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {// 解析参数BackupJobVO vo = JSONObject.parseObject(context.getJobDetail().getJobDataMap().getString(QuartzManager.PARAM_KEY), BackupJobVO.class);// 开始备份mysqlTool.saveBackUp(vo.getDbId(), vo.getHost(), vo.getPort(), vo.getDbName(), vo.getTables(), vo.getDataType(), vo.getUsername(), vo.getPassword(), new Date(), BackupCategoryEnum.AUTO);}
}

获取到备份参数,包括:主机地址,端口,用户名,密码,数据库名等,就能执行备份任务了

好了,我们的数据库备份管理系统大致就介绍完了,有感兴趣的朋友可以下载我的开源项目:

https://gitee.com/asurplus/db-backup

如您在阅读中发现不足,欢迎留言!!!

【SpringBoot】70、SpringBoot实现MySQL数据库自动备份管理系统相关推荐

  1. mysql nb3 备份_通过Navicat进行Mysql数据库自动备份与还原

    Mysql数据库自动备份流程 Navicat版本为:Navicat 12.0.26 例:test为用于测试自动备份的数据库,里面有表t_person,表中有两条数据. 1.点击"自动运行&q ...

  2. linux 备份mysql并上传_实现Linux中Mysql数据库自动备份并上传到远程FTP服务器

    这篇文章很有分享价值,因为我们在实际的生产环境中需要将数据库进行自动备份,然后上传到指定的位置,当然也可以像以下文章中所讲的一样,上传到你指定的FTP服务器中,从而实现Mysql数据库自动备份并上传到 ...

  3. windows环境设置mysql数据库自动备份(测试成功)

    windows环境设置mysql数据库自动备份(测试成功) 要实现数据库的自动备份就需要一下两步: 利用MySQL提供的备份命令mysqldump 结合Windows的任务计划程序 实现步骤 编写脚本 ...

  4. windows环境mysql数据库自动备份

    1:mysql数据库备份命令 执行 mysqldump -u username -p database > c:/bak.sql 再次输入mysql密码,导出完成! 2:编写bat脚本 @ech ...

  5. mysql web备份软件_GitHub - toolzone/mysql_web_backup: mysql数据库自动备份,web网站自动备份shell脚本...

    注意: Mysql_backup.sh 为 mysql 自动备份 脚本,配合 crontab命令 用来管理需要周期性执行任务 Web_backup.sh 为 web文件 自动备份 脚本,配合 cron ...

  6. mysql数据库备份自动备份_设置mysql数据库自动备份

    由于项目需要,在windows下的mysql实现数据库自动备份.经资料查询和尝试,得出方法有两种: 1.使用windows自带的任务计划,然后定时执行一个数据库备份的脚本. 2.使用mysql管理工具 ...

  7. Linux——MySQL数据库自动备份

    Linux如何将Mysql数据库自动从一台服务器备份到另一台服务器 一.概述: 备份是容灾的基础,是指为防止系统出现操作失误或系统故障导致数据丢失,而将全部或部分数据集合从应用主机的硬盘或阵列复制到其 ...

  8. crontab 每天凌晨12点定时器_Linux下使用crontab实现mysql数据库自动备份

    大家在做开发的时候,数据是很重要的,本文将介绍MySQL数据库如何在Linux系统上面进行自动备份 创建备份目录 选择/home目录,在该目录下创建backup文件夹来存放数据库备份文件: #cd / ...

  9. mac上 mysql数据库自动备份

    创建 mysqlbak.sh脚本文件,对数据库进行备份 #!/bin/bash base="/Users/xingxing/Documents/mysql/data" date=$ ...

最新文章

  1. mysql语句优化百条_优化mysql语句
  2. usessl mysql_mysql数据库连接useSSL=true
  3. UVA - 11491 Erasing and Winning(奖品的价值)(贪心)
  4. boost::basic_string_view相关的测试程序
  5. 最详细的YOLOv3论文笔记
  6. c语言 勒让德多项式,2406: C语言习题 求n阶勒让德多项式(示例代码)
  7. 在 Windows Azure 虚拟机上运行 SQL Server 工作负荷的十大注意事项
  8. linux rm 命令删除文件恢复_【Linux】恢复误删除的文件或目录
  9. Origin 2019b 图文安装教程及下载(附安装包)
  10. chrome浏览器 自带网页截取长图功能
  11. WPF 设置本地打印的纸张和方向
  12. 虚拟机虚拟磁盘文件格式转换
  13. 学生学籍管理系统_学生登陆系统查询与修改信息
  14. 报错:Base64-encoded key bytes may only be specified for HMAC signatures.
  15. 笔记本屏幕颜色校证,有效解决屏幕发白、刺眼问题
  16. HTML5及CSS3基础知识(持续更新)
  17. 命令行发送SMTP协议邮件(163邮箱)
  18. 梳理学习技术的脉络,助你一臂之力
  19. AUTOSAR实战教程 - 通信协议栈CAN_CANIF_PDUR_CANTP_COM_XCP_ECUC配置一网打尽
  20. Java显示当前月的日历

热门文章

  1. 关于软件测试行业现状的一些思考
  2. 欧盟人工智能立法提案的核心思想 及未来影响分析
  3. 【电巢】什么是EMC测试?EMC测试又是如何分类的?
  4. MyEclipse更换主题皮肤
  5. 微机原理真题2019年,错题整理
  6. 信用卡客户风险评估-聚类分析实验报告(python)
  7. OAI搭建之SIM卡
  8. 树的应用:Tree Traversals Again
  9. KEPServerEX 6.9 之 Fanuc Focas 驱动-CNC Data的使用(中文版)
  10. ftp下载文件失败问题记录