SpringBoot实现MySQL数据库备份与还原

您所在的位置:网站首页 mysql备份数据恢复 SpringBoot实现MySQL数据库备份与还原

SpringBoot实现MySQL数据库备份与还原

2024-07-16 16:30| 来源: 网络整理| 查看: 265

前言:

这篇文章已经构思很久了,之前说过的,可以看下这篇文章MySQL数据库备份与恢复-使用MySQLDump记录 | 框架师,是一个可视化备份MySQL的需求,我们平台是BS的架构,有一个WEB 页面,客户需求是在页面上对所有的平台数据执行备份和恢复操作,那么就需要使用代码去调用MySQL备份和恢复的指令,下面是具体实现步骤;

MySQL备份表设计

具体SQL:

CREATE TABLE IF NOT EXISTS `mysql_backups` ( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT COMMENT '主键id', `mysql_ip` VARCHAR ( 15 ) DEFAULT NULL COMMENT '数据库IP', `mysql_port` VARCHAR ( 5 ) DEFAULT NULL COMMENT '数据库端口', `mysql_cmd` VARCHAR ( 230 ) DEFAULT NULL COMMENT '备份命令', `mysql_back_cmd` VARCHAR ( 230 ) DEFAULT NULL COMMENT '恢复命令', `database_name` VARCHAR ( 20 ) DEFAULT NULL COMMENT '数据库名称', `backups_path` VARCHAR ( 50 ) DEFAULT NULL COMMENT '备份数据地址', `backups_name` VARCHAR ( 50 ) DEFAULT NULL COMMENT '备份文件名称', `operation` INT ( 11 ) DEFAULT NULL COMMENT '操作次数', `status` INT ( 1 ) DEFAULT NULL COMMENT '数据状态(1正常,-1删除)', `recovery_time` DATETIME DEFAULT NULL COMMENT '恢复时间', `create_time` DATETIME DEFAULT NULL COMMENT '备份时间', PRIMARY KEY ( `id` ), INDEX baskups_index ( mysql_ip, mysql_port, backups_path, database_name,backups_name) USING BTREE COMMENT '索引' ) ENGINE = INNODB AUTO_INCREMENT = 1 CHARSET = UTF8 ROW_FORMAT = COMPACT COMMENT = 'MySQL数据备份表';

数据状态这个字段可加可不加,我的视角是这个备份属于永久存储,不可删除的,所以前端界面上不能有删除按钮,但是后台可能会对一些数据做操作,就加了status这个字段。

实体类设计 import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import lombok.Data; import java.util.Date; /** * Software:IntelliJ IDEA 2021.2 x64 * Date: 2021/9/16 14:47 * ClassName:SystemMysqlBackups * 类描述: MySQL备份实体 */ @Data @TableName("mysql_backups") public class SystemMysqlBackups { /** * 主键id */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * MySQL服务器IP地址 */ @TableField("mysql_ip") private String mysqlIp; /** * MySQL服务器端口号 */ @TableField("mysql_port") private String mysqlPort; /** * MySQL服务器端口号 */ @TableField("database_name") private String databaseName; /** * MySQL备份指令 */ @TableField("mysql_cmd") private String mysqlCmd; /** * MySQL恢复指令 */ @TableField("mysql_back_cmd") private String mysqlBackCmd; /** * MySQL备份存储地址 */ @TableField("backups_path") private String backupsPath; /** * MySQL备份文件名称 */ @TableField("backups_name") private String backupsName; /** * 操作次数 */ @TableField("operation") private Integer operation; /** * 数据状态 */ @TableField("status") private Integer status; /** * 恢复时间 */ @TableField("recovery_time") private Date recoveryTime; /** * 备份时间 */ @TableField("create_time") private Date createTime; }

注解说明:

@Data:Lombok简化实体类注解,不了解的小伙伴可以查看我之前写过的Lombok | 框架师一文@TableName:MybatisPlus的注解,标识表名@TableId:标识主键,设置主键增长类型@TableField:标识表字段 mapper和映射文件 mapper 接口代码: import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zj.module.repository.model.system.backups.SystemMysqlBackups; import org.apache.ibatis.annotations.Param; import java.util.List; /** * Software:IntelliJ IDEA 2021.2 x64 * Date: 2021/9/16 15:01 * InterfaceName:SystemMysqlBackupsMapper * 接口描述: MySQL备份接口 */ public interface SystemMysqlBackupsMapper extends BaseMapper { /** * 查询所有备份数据 */ List selectBackupsList(); /** * 根据ID查询 */ SystemMysqlBackups selectListId(@Param("id") Long id); }

以上两个方法可以不写,但是我们公司使用的 MybatisPlus 版本明明都配置好了逻辑删除,无法使用就邪门💢,所以只能写这些重复的轮子。对了,我们公司使用的MybatisPlus版本是1.0.5。有知道的小伙伴可以在下方评论告诉我一下。

映射文件代码: id as id, `mysql_ip` as mysqlIp, `mysql_port` as mysqlPort, `mysql_cmd` as mysqlCmd, `mysql_back_cmd` as mysqlBackCmd, `database_name` as databaseName, `backups_path` as backupsPath, `backups_name` as backupsName, `operation` as operation, `status` as status, `recovery_time` as recoveryTime, `create_time` as createTime SELECT * FROM `mysql_backups` WHERE `status` != 0 AND id = #{id} SELECT * FROM `mysql_backups` WHERE `status` != 0 ORDER BY create_time DESC Service 接口和实现类 service 接口 import com.baomidou.mybatisplus.service.IService; import com.mobaijun.module.model.system.backups.SystemMysqlBackups; import java.util.List; /** * Software:IntelliJ IDEA 2021.2 x64 * Author: https://www.mobaijun.com * Date: 2021/9/16 15:19 * ClassName:SystemMysqlBackupsservice * 类描述: MySQL备份接口 */ public interface SystemMysqlBackupsService extends IService { /** * 查询所有备份数据 */ List selectBackupsList(); /** * mysql备份接口 */ Object mysqlBackups(String filePath, String url, String userName, String password); /** * 根据ID查询 */ SystemMysqlBackups selectListId(Long id); /** * 恢复数据库 * * @param smb 恢复对象 * @param userName 数据库用户名 * @param password 数据库密码 * @return */ Object rollback(SystemMysqlBackups smb, String userName, String password); }

以上代码都有注释,这块呼吁大家向我学习,我们公司有同事写代码从来不加注释💢,看他代码很💥

实现类: import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.mobaijun.module.core.constant.common.Constants; import com.mobaijun.module.core.tips.ErrorTip; import com.mobaijun.module.dao.system.backups.SystemMysqlBackupsMapper; import com.mobaijun.module.model.system.backups.SystemMysqlBackups; import com.mobaijun.module.service.system.backups.SystemMysqlBackupsService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Date; import java.util.List; /** * Software:IntelliJ IDEA 2021.2 x64 * Date: 2021/9/16 15:19 * ClassName:SystemMysqlBackupsService * 类描述: MySQL备份实现 */ @Slf4j @Service public class SystemMysqlBackupsServiceImpl extends ServiceImpl implements SystemMysqlBackupsService { @Resource private SystemMysqlBackupsMapper systemMysqlBackupsMapper; @Override public List selectBackupsList() { return systemMysqlBackupsMapper.selectBackupsList(); } @Override public Object mysqlBackups(String filePath, String url, String userName, String password) { // 获取ip final String ip = url.substring(13, 22); // 获取端口号 final String port = url.substring(23, 27); // 获取数据库名称 final String database_name = url.substring(28, 42); // 数据库文件名称 StringBuilder mysqlFileName = new StringBuilder() .append(Constants.DATA_BASE_NAME) .append("_") .append(DateUtil.format(new Date(), "yyyy-MM-dd-HH-mm-ss")) .append(Constants.FILE_SUFFIX); // 备份命令 StringBuilder cmd = new StringBuilder() .append("mysqldump ") .append("--no-tablespaces ") .append("-h") .append(ip) .append(" -u") .append(userName) .append(" -p") .append(password) // 排除MySQL备份表 .append(" --ignore-table ") .append(database_name) .append(".mysql_backups ") .append(database_name) .append(" > ") .append(filePath) .append(mysqlFileName); // 判断文件是否保存成功 if (!FileUtil.exist(filePath)) { FileUtil.mkdir(filePath); return new ErrorTip(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.value(), "备份失败,文件保存异常,请查看文件内容后重新尝试!"); } // 获取操作系统名称 String osName = System.getProperty("os.name").toLowerCase(); String[] command = new String[0]; if (Constants.isSystem(osName)) { // Windows command = new String[]{"cmd", "/c", String.valueOf(cmd)}; } else { // Linux command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)}; } SystemMysqlBackups smb = new SystemMysqlBackups(); // 备份信息存放到数据库 smb.setMysqlIp(ip); smb.setMysqlPort(port); smb.setBackupsName(String.valueOf(mysqlFileName)); smb.setDatabaseName(database_name); smb.setMysqlCmd(String.valueOf(cmd)); smb.setBackupsPath(filePath); smb.setCreateTime(DateTime.now()); smb.setStatus(1); smb.setOperation(0); systemMysqlBackupsMapper.insert(smb); log.error("数据库备份命令为:{}", cmd); // 获取Runtime实例 Process process = null; try { process = Runtime.getRuntime().exec(command); if (process.waitFor() == 0) { log.info("Mysql 数据库备份成功,备份文件名:{}", mysqlFileName); } else { return new ErrorTip(HttpStatus.INTERNAL_SERVER_ERROR.value(), "网络异常,数据库备份失败"); } } catch (Exception e) { e.printStackTrace(); return new ErrorTip(HttpStatus.INTERNAL_SERVER_ERROR.value(), "网络异常,数据库备份失败"); } return smb; } @Override public SystemMysqlBackups selectListId(Long id) { return systemMysqlBackupsMapper.selectListId(id); } @Override public Object rollback(SystemMysqlBackups smb, String userName, String password) { // 备份路径和文件名 StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName()); if (!FileUtil.exist(String.valueOf(realFilePath))) { return new ErrorTip(HttpStatus.NOT_FOUND.value(), "文件不存在,恢复失败,请查看目录内文件是否存在后重新尝试!"); } StringBuilder cmd = new StringBuilder() .append("mysql -h") .append(smb.getMysqlIp()) .append(" -u") .append(userName) .append(" -p") .append(password) .append(" ") .append(smb.getDatabaseName()) .append(" < ") .append(realFilePath); String[] command = new String[0]; log.error("数据库恢复命令为:{}", cmd); // 获取操作系统名称 String osName = System.getProperty("os.name").toLowerCase(); if (Constants.isSystem(osName)) { // Windows command = new String[]{"cmd", "/c", String.valueOf(cmd)}; } else { // Linux command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)}; } // 恢复指令写入到数据库 smb.setMysqlBackCmd(String.valueOf(cmd)); // 更新操作次数 smb.setRecoveryTime(DateTime.now()); smb.setOperation(smb.getOperation() + 1); // 获取Runtime实例 Process process = null; try { process = Runtime.getRuntime().exec(command); if (process.waitFor() == 0) { log.error("Mysql 数据库恢复成功,恢复文件名:{}", realFilePath); } else { return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常,恢复失败,请稍后重新尝试!"); } } catch (Exception e) { e.printStackTrace(); return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常,恢复失败,请稍后重新尝试!"); } return smb; } }

写的工具类方法如下:

/** * 文件后缀 */ public static final String FILE_SUFFIX = ".sql"; /** * 判断操作系统类型、Linux|Windows */ public static boolean isSystem(String osName) { Boolean flag = null; if (osName.startsWith("windows")) { flag = true; } else if (osName.startsWith("linux")) { flag = false; } return flag; } 控制器

代码如下:

import com.mobaijun.module.core.constant.common.Constants; import com.mobaijun.module.core.tips.ErrorTip; import com.mobaijun.module.core.tips.SuccessTip; import com.mobaijun.module.model.system.backups.SystemMysqlBackups; import com.mobaijun.module.service.system.backups.SystemMysqlBackupsService; import com.mobaijun.module.web.annotion.ApiJsonObject; import com.mobaijun.module.web.annotion.ApiJsonProperty; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; /** * Software:IntelliJ IDEA 2021.2 x64 * Author: https://www.mobaijun.com * Date: 2021/9/16 14:45 * ClassName:SystemMysqlBackupsController * 类描述: MySQL数据备份接口 */ @RestController @Api(description = "MySQL数据备份") @RequestMapping(value = "/api/system/baskups") public class SystemMysqlBackupsController { /** * 数据库用户名 */ @Value("${spring.datasource.username}") private String userName; /** * 数据库密码 */ @Value("${spring.datasource.password}") private String password; /** * 数据库url */ @Value("${spring.datasource.url}") private String url; /** * Windows数据库备份地址 */ @Value("${spring.datasource.win-path}") private String windowsPath; /** * Linux数据库备份地址 */ @Value("${spring.datasource.linux-path}") private String linuxPath; @Autowired private SystemMysqlBackupsService systemMysqlBackupsService; @ApiOperation(value = "获取所有备份数据列表") @GetMapping("/backupsList") public Object backupsList() { List systemMysqlBackups = systemMysqlBackupsService.selectBackupsList(); return new SuccessTip(systemMysqlBackups); } @ApiOperation(value = "MySQL备份") @PostMapping("/mysqlBackups") public Object mysqlBackups() { String path = null; // 获取操作系统名称 String osName = System.getProperty("os.name").toLowerCase(); if (Constants.isSystem(osName)) { // Windows path = this.windowsPath; } else { // Linux path = this.linuxPath; } // 数据库用户名 String userName = this.userName; // 数据库密码 String password = this.password; // 数据库地址 String url = this.url; // 调用备份 Object systemMysqlBackups = systemMysqlBackupsService.mysqlBackups(path, url, userName, password); return new SuccessTip(systemMysqlBackups); } @ApiOperation(value = "恢复数据库") @PutMapping("/rollback") public Object rollback(@ApiJsonObject(name = "恢复数据库", value = { @ApiJsonProperty(name = "id", example = "1", value = "数据id", dataType = "long", required = true)}) @ApiParam(value = "恢复数据库") @RequestBody Map map) { Long id = Long.valueOf(map.get("id").toString()); if (id == null) { return new ErrorTip(HttpStatus.INTERNAL_SERVER_ERROR.value(), "id不能为null,请重新尝试!"); } // 数据库用户名 String userName = this.userName; // 数据库密码 String password = this.password; // 根据id查询查询已有的信息 SystemMysqlBackups smb = systemMysqlBackupsService.selectListId(id); // 恢复数据库 Object rollback = systemMysqlBackupsService.rollback(smb, userName, password); // 更新操作次数 systemMysqlBackupsService.updateById(smb); return new SuccessTip(rollback); } }

最终效果:

 

  加端端老师免费领取更多Java资料



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3